EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c

Go to the documentation of this file.
00001 
00015 #include "AtaAtapiPassThru.h"
00016 
00026 UINT32
00027 EFIAPI
00028 AhciReadReg (
00029   IN EFI_PCI_IO_PROTOCOL  *PciIo,
00030   IN  UINT32              Offset
00031   )
00032 {
00033   UINT32                  Data;
00034 
00035   ASSERT (PciIo != NULL);
00036   
00037   Data = 0;
00038 
00039   PciIo->Mem.Read (
00040                PciIo,
00041                EfiPciIoWidthUint32,
00042                EFI_AHCI_BAR_INDEX,
00043                (UINT64) Offset,
00044                1,
00045                &Data
00046                );
00047 
00048   return Data;
00049 }
00050 
00059 VOID
00060 EFIAPI
00061 AhciWriteReg (
00062   IN EFI_PCI_IO_PROTOCOL  *PciIo,
00063   IN UINT32               Offset,
00064   IN UINT32               Data
00065   )
00066 {
00067   ASSERT (PciIo != NULL);
00068 
00069   PciIo->Mem.Write (
00070                PciIo,
00071                EfiPciIoWidthUint32,
00072                EFI_AHCI_BAR_INDEX,
00073                (UINT64) Offset,
00074                1,
00075                &Data
00076                );
00077 
00078   return ;
00079 }
00080 
00089 VOID
00090 EFIAPI
00091 AhciAndReg (
00092   IN EFI_PCI_IO_PROTOCOL  *PciIo,
00093   IN UINT32               Offset,
00094   IN UINT32               AndData
00095   )
00096 {
00097   UINT32 Data;
00098   
00099   ASSERT (PciIo != NULL);
00100 
00101   Data  = AhciReadReg (PciIo, Offset);
00102 
00103   Data &= AndData;
00104 
00105   AhciWriteReg (PciIo, Offset, Data);
00106 }
00107 
00116 VOID
00117 EFIAPI
00118 AhciOrReg (
00119   IN EFI_PCI_IO_PROTOCOL  *PciIo,
00120   IN UINT32               Offset,
00121   IN UINT32               OrData
00122   )
00123 {
00124   UINT32 Data;
00125 
00126   ASSERT (PciIo != NULL);
00127 
00128   Data  = AhciReadReg (PciIo, Offset);
00129 
00130   Data |= OrData;
00131 
00132   AhciWriteReg (PciIo, Offset, Data);
00133 }
00134 
00148 EFI_STATUS
00149 EFIAPI
00150 AhciWaitMmioSet (
00151   IN  EFI_PCI_IO_PROTOCOL       *PciIo,
00152   IN  UINTN                     Offset,
00153   IN  UINT32                    MaskValue,
00154   IN  UINT32                    TestValue,
00155   IN  UINT64                    Timeout
00156   )
00157 {
00158   UINT32     Value;  
00159   UINT32     Delay;
00160 
00161   Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
00162 
00163   do {
00164     //
00165     // Access PCI MMIO space to see if the value is the tested one.
00166     //
00167     Value = AhciReadReg (PciIo, (UINT32) Offset) & MaskValue;
00168 
00169     if (Value == TestValue) {
00170       return EFI_SUCCESS;
00171     }
00172 
00173     //
00174     // Stall for 100 microseconds.
00175     //
00176     MicroSecondDelay (100);
00177 
00178     Delay--;
00179 
00180   } while (Delay > 0);
00181 
00182   return EFI_TIMEOUT;
00183 }
00184 
00197 EFI_STATUS
00198 EFIAPI
00199 AhciWaitMemSet (
00200   IN  EFI_PHYSICAL_ADDRESS      Address,
00201   IN  UINT32                    MaskValue,
00202   IN  UINT32                    TestValue,
00203   IN  UINT64                    Timeout
00204   )
00205 {
00206   UINT32     Value;  
00207   UINT32     Delay;
00208 
00209   Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
00210 
00211   do {
00212     //
00213     // Access sytem memory to see if the value is the tested one.
00214     //
00215     // The system memory pointed by Address will be updated by the
00216     // SATA Host Controller, "volatile" is introduced to prevent
00217     // compiler from optimizing the access to the memory address
00218     // to only read once.
00219     //
00220     Value  = *(volatile UINT32 *) (UINTN) Address;
00221     Value &= MaskValue;
00222 
00223     if (Value == TestValue) {
00224       return EFI_SUCCESS;
00225     }
00226 
00227     //
00228     // Stall for 100 microseconds.
00229     //
00230     MicroSecondDelay (100);
00231 
00232     Delay--;
00233 
00234   } while (Delay > 0);
00235 
00236   return EFI_TIMEOUT;
00237 }
00238 
00252 EFI_STATUS
00253 EFIAPI
00254 AhciCheckMemSet (
00255   IN     UINTN                     Address,
00256   IN     UINT32                    MaskValue,
00257   IN     UINT32                    TestValue,
00258   IN OUT UINTN                     *RetryTimes OPTIONAL
00259   )
00260 {
00261   UINT32     Value;
00262 
00263   if (RetryTimes != NULL) {
00264     (*RetryTimes)--;
00265   }
00266  
00267   Value  = *(volatile UINT32 *) Address;
00268   Value &= MaskValue;
00269 
00270   if (Value == TestValue) {
00271     return EFI_SUCCESS;
00272   }
00273 
00274   if ((RetryTimes != NULL) && (*RetryTimes == 0)) {
00275     return EFI_TIMEOUT;
00276   } else {
00277     return EFI_NOT_READY;
00278   }
00279 }
00280 
00296 EFI_STATUS
00297 EFIAPI
00298 AhciCheckDeviceStatus (
00299   IN  EFI_PCI_IO_PROTOCOL    *PciIo,
00300   IN  UINT8                  Port
00301   )
00302 {
00303   UINT32      Data;
00304   UINT32      Offset;
00305 
00306   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
00307 
00308   Data   = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
00309 
00310   if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {
00311     return EFI_SUCCESS;
00312   }
00313 
00314   return EFI_NOT_READY;
00315 }
00316 
00326 VOID
00327 EFIAPI
00328 AhciClearPortStatus (
00329   IN  EFI_PCI_IO_PROTOCOL    *PciIo,
00330   IN  UINT8                  Port
00331   )  
00332 {
00333   UINT32 Offset;
00334 
00335   //
00336   // Clear any error status
00337   //
00338   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
00339   AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
00340 
00341   //
00342   // Clear any port interrupt status
00343   //
00344   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
00345   AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
00346 
00347   //
00348   // Clear any HBA interrupt status
00349   //
00350   AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));
00351 }
00352 
00362 VOID
00363 EFIAPI
00364 AhciDumpPortStatus (
00365   IN     EFI_PCI_IO_PROTOCOL        *PciIo,
00366   IN     UINT8                      Port,
00367   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock
00368   )
00369 {
00370   UINT32               Offset;
00371   UINT32               Data;
00372 
00373   ASSERT (PciIo != NULL);
00374 
00375   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
00376   Data   = AhciReadReg (PciIo, Offset);
00377 
00378   if (AtaStatusBlock != NULL) {
00379     ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
00380 
00381     AtaStatusBlock->AtaStatus  = (UINT8)Data;
00382     if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {
00383       AtaStatusBlock->AtaError = (UINT8)(Data >> 8);
00384     }
00385   }
00386 }
00387 
00388 
00401 EFI_STATUS
00402 EFIAPI
00403 AhciEnableFisReceive (
00404   IN  EFI_PCI_IO_PROTOCOL       *PciIo,
00405   IN  UINT8                     Port,
00406   IN  UINT64                    Timeout
00407   )
00408 {
00409   UINT32 Offset;
00410 
00411   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
00412   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);
00413 
00414   return AhciWaitMmioSet (
00415            PciIo, 
00416            Offset,
00417            EFI_AHCI_PORT_CMD_FR,
00418            EFI_AHCI_PORT_CMD_FR,
00419            Timeout
00420            );
00421 }
00422 
00436 EFI_STATUS
00437 EFIAPI
00438 AhciDisableFisReceive (
00439   IN  EFI_PCI_IO_PROTOCOL       *PciIo,
00440   IN  UINT8                     Port,
00441   IN  UINT64                    Timeout
00442   )  
00443 {
00444   UINT32 Offset;
00445   UINT32 Data;
00446 
00447   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
00448   Data   = AhciReadReg (PciIo, Offset);
00449 
00450   //
00451   // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
00452   //
00453   if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
00454     return EFI_UNSUPPORTED;
00455   }
00456   
00457   //
00458   // Check if the Fis receive DMA engine for the port is running.
00459   //
00460   if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {
00461     return EFI_SUCCESS;
00462   }
00463 
00464   AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
00465 
00466   return AhciWaitMmioSet (
00467            PciIo,
00468            Offset,
00469            EFI_AHCI_PORT_CMD_FR,
00470            0,
00471            Timeout
00472            );
00473 }
00474 
00475 
00476 
00493 VOID
00494 EFIAPI
00495 AhciBuildCommand (
00496   IN     EFI_PCI_IO_PROTOCOL        *PciIo,
00497   IN     EFI_AHCI_REGISTERS         *AhciRegisters,
00498   IN     UINT8                      Port,
00499   IN     UINT8                      PortMultiplier,
00500   IN     EFI_AHCI_COMMAND_FIS       *CommandFis,
00501   IN     EFI_AHCI_COMMAND_LIST      *CommandList,
00502   IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,
00503   IN     UINT8                      AtapiCommandLength,
00504   IN     UINT8                      CommandSlotNumber,
00505   IN OUT VOID                       *DataPhysicalAddr,
00506   IN     UINT64                     DataLength
00507   )   
00508 {
00509   UINT64     BaseAddr;
00510   UINT64     PrdtNumber;
00511   UINT64     PrdtIndex;
00512   UINTN      RemainedData;
00513   UINTN      MemAddr;
00514   DATA_64    Data64;
00515   UINT32     Offset;
00516 
00517   //
00518   // Filling the PRDT
00519   //  
00520   PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;
00521 
00522   //
00523   // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
00524   // It also limits that the maximum amount of the PRDT entry in the command table
00525   // is 65535.
00526   //
00527   ASSERT (PrdtNumber <= 65535);
00528 
00529   Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
00530 
00531   BaseAddr = Data64.Uint64;
00532   
00533   ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
00534     
00535   ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
00536 
00537   CommandFis->AhciCFisPmNum = PortMultiplier;
00538   
00539   CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
00540 
00541   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
00542   if (AtapiCommand != NULL) {
00543     CopyMem (
00544       &AhciRegisters->AhciCommandTable->AtapiCmd,
00545       AtapiCommand,
00546       AtapiCommandLength
00547       );
00548 
00549     CommandList->AhciCmdA = 1;
00550     CommandList->AhciCmdP = 1;
00551     CommandList->AhciCmdC = (DataLength == 0) ? 1 : 0;
00552 
00553     AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
00554   } else {
00555     AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
00556   }
00557   
00558   RemainedData = (UINTN) DataLength;
00559   MemAddr      = (UINTN) DataPhysicalAddr;
00560   CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
00561   
00562   for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
00563     if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {
00564       AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;
00565     } else {
00566       AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;
00567     }
00568 
00569     Data64.Uint64 = (UINT64)MemAddr;
00570     AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba  = Data64.Uint32.Lower32;
00571     AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;
00572     RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;
00573     MemAddr      += EFI_AHCI_MAX_DATA_PER_PRDT;
00574   }
00575 
00576   //
00577   // Set the last PRDT to Interrupt On Complete
00578   //
00579   if (PrdtNumber > 0) {
00580     AhciRegisters->AhciCommandTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;
00581   }
00582 
00583   CopyMem (
00584     (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
00585     CommandList,
00586     sizeof (EFI_AHCI_COMMAND_LIST)
00587     );  
00588 
00589   Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;
00590   AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba  = Data64.Uint32.Lower32;
00591   AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
00592   AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp   = PortMultiplier;
00593 
00594 }
00595 
00603 VOID
00604 EFIAPI
00605 AhciBuildCommandFis (
00606   IN OUT EFI_AHCI_COMMAND_FIS    *CmdFis,
00607   IN     EFI_ATA_COMMAND_BLOCK   *AtaCommandBlock
00608   )
00609 {
00610   ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
00611 
00612   CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;
00613   //
00614   // Indicator it's a command
00615   //
00616   CmdFis->AhciCFisCmdInd      = 0x1; 
00617   CmdFis->AhciCFisCmd         = AtaCommandBlock->AtaCommand;
00618 
00619   CmdFis->AhciCFisFeature     = AtaCommandBlock->AtaFeatures;
00620   CmdFis->AhciCFisFeatureExp  = AtaCommandBlock->AtaFeaturesExp;
00621 
00622   CmdFis->AhciCFisSecNum      = AtaCommandBlock->AtaSectorNumber;
00623   CmdFis->AhciCFisSecNumExp   = AtaCommandBlock->AtaSectorNumberExp;
00624 
00625   CmdFis->AhciCFisClyLow      = AtaCommandBlock->AtaCylinderLow;
00626   CmdFis->AhciCFisClyLowExp   = AtaCommandBlock->AtaCylinderLowExp;
00627 
00628   CmdFis->AhciCFisClyHigh     = AtaCommandBlock->AtaCylinderHigh;
00629   CmdFis->AhciCFisClyHighExp  = AtaCommandBlock->AtaCylinderHighExp;
00630 
00631   CmdFis->AhciCFisSecCount    = AtaCommandBlock->AtaSectorCount;
00632   CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
00633 
00634   CmdFis->AhciCFisDevHead     = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
00635 }
00636 
00662 EFI_STATUS
00663 EFIAPI
00664 AhciPioTransfer (
00665   IN     EFI_PCI_IO_PROTOCOL        *PciIo,
00666   IN     EFI_AHCI_REGISTERS         *AhciRegisters,
00667   IN     UINT8                      Port,
00668   IN     UINT8                      PortMultiplier,
00669   IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,
00670   IN     UINT8                      AtapiCommandLength,  
00671   IN     BOOLEAN                    Read,  
00672   IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,
00673   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,
00674   IN OUT VOID                       *MemoryAddr,
00675   IN     UINT32                     DataCount,
00676   IN     UINT64                     Timeout,
00677   IN     ATA_NONBLOCK_TASK          *Task
00678   )
00679 {
00680   EFI_STATUS                    Status;
00681   UINTN                         FisBaseAddr;
00682   UINTN                         Offset;
00683   EFI_PHYSICAL_ADDRESS          PhyAddr;
00684   VOID                          *Map;
00685   UINTN                         MapLength;
00686   EFI_PCI_IO_PROTOCOL_OPERATION Flag;
00687   UINT32                        Delay;
00688   EFI_AHCI_COMMAND_FIS          CFis;
00689   EFI_AHCI_COMMAND_LIST         CmdList; 
00690   UINT32                        PortTfd;
00691   UINT32                        PrdCount;
00692 
00693   if (Read) {
00694     Flag = EfiPciIoOperationBusMasterWrite;
00695   } else {
00696     Flag = EfiPciIoOperationBusMasterRead;
00697   }
00698 
00699   //
00700   // construct command list and command table with pci bus address
00701   //
00702   MapLength = DataCount;
00703   Status = PciIo->Map (
00704                     PciIo,
00705                     Flag,
00706                     MemoryAddr,
00707                     &MapLength,
00708                     &PhyAddr,
00709                     &Map
00710                     );
00711 
00712   if (EFI_ERROR (Status) || (DataCount != MapLength)) {
00713     return EFI_BAD_BUFFER_SIZE;
00714   }
00715   
00716   //
00717   // Package read needed
00718   //
00719   AhciBuildCommandFis (&CFis, AtaCommandBlock);
00720 
00721   ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
00722 
00723   CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
00724   CmdList.AhciCmdW   = Read ? 0 : 1;
00725 
00726   AhciBuildCommand (
00727     PciIo,
00728     AhciRegisters,
00729     Port,
00730     PortMultiplier,
00731     &CFis,
00732     &CmdList,
00733     AtapiCommand,
00734     AtapiCommandLength,
00735     0,
00736     (VOID *)(UINTN)PhyAddr,
00737     DataCount
00738     );    
00739   
00740   Status = AhciStartCommand (
00741              PciIo,
00742              Port,
00743              0,
00744              Timeout
00745              );
00746   if (EFI_ERROR (Status)) {
00747     goto Exit;
00748   }
00749 
00750   //
00751   // Check the status and wait the driver sending data
00752   //
00753   FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
00754 
00755   if (Read && (AtapiCommand == 0)) {
00756     //
00757     // Wait device sends the PIO setup fis before data transfer
00758     //
00759     Status = EFI_TIMEOUT;
00760     Delay  = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
00761     do {
00762       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
00763       PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
00764 
00765       if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
00766         Status = EFI_DEVICE_ERROR;
00767         break;
00768       }
00769       Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
00770 
00771       Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);
00772       if (!EFI_ERROR (Status)) {
00773         PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
00774         if (PrdCount == DataCount) {
00775           break;
00776         }
00777       }
00778 
00779       Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
00780       Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);
00781       if (!EFI_ERROR (Status)) {
00782         Status = EFI_DEVICE_ERROR;
00783         break;
00784       }
00785 
00786       //
00787       // Stall for 100 microseconds.
00788       //
00789       MicroSecondDelay(100);
00790 
00791       Delay--;
00792     } while (Delay > 0);
00793   } else {
00794     //
00795     // Wait for D2H Fis is received
00796     //
00797     Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
00798     Status = AhciWaitMemSet (
00799                Offset,
00800                EFI_AHCI_FIS_TYPE_MASK,
00801                EFI_AHCI_FIS_REGISTER_D2H,
00802                Timeout
00803                );
00804 
00805     if (EFI_ERROR (Status)) {
00806       goto Exit;
00807     }
00808 
00809     Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
00810     PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
00811     if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
00812       Status = EFI_DEVICE_ERROR;
00813     }
00814   }
00815 
00816 Exit:
00817   AhciStopCommand (
00818     PciIo,
00819     Port,
00820     Timeout
00821     );
00822   
00823   AhciDisableFisReceive (
00824     PciIo,
00825     Port,
00826     Timeout
00827     );
00828 
00829   PciIo->Unmap (
00830     PciIo,
00831     Map
00832     );
00833 
00834   AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);
00835 
00836   return Status;
00837 }
00838 
00864 EFI_STATUS
00865 EFIAPI
00866 AhciDmaTransfer (
00867   IN     ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
00868   IN     EFI_AHCI_REGISTERS         *AhciRegisters,
00869   IN     UINT8                      Port,
00870   IN     UINT8                      PortMultiplier,
00871   IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,
00872   IN     UINT8                      AtapiCommandLength,
00873   IN     BOOLEAN                    Read,  
00874   IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,
00875   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,
00876   IN OUT VOID                       *MemoryAddr,
00877   IN     UINT32                     DataCount,
00878   IN     UINT64                     Timeout,
00879   IN     ATA_NONBLOCK_TASK          *Task
00880   )
00881 {
00882   EFI_STATUS                    Status;
00883   UINTN                         Offset;
00884   EFI_PHYSICAL_ADDRESS          PhyAddr;
00885   VOID                          *Map;
00886   UINTN                         MapLength;
00887   EFI_PCI_IO_PROTOCOL_OPERATION Flag;
00888   EFI_AHCI_COMMAND_FIS          CFis;
00889   EFI_AHCI_COMMAND_LIST         CmdList;
00890   UINTN                         FisBaseAddr;
00891   UINT32                        PortTfd;
00892 
00893   EFI_PCI_IO_PROTOCOL           *PciIo;
00894   EFI_TPL                       OldTpl;
00895 
00896   Map   = NULL;
00897   PciIo = Instance->PciIo;
00898 
00899   if (PciIo == NULL) {
00900     return EFI_INVALID_PARAMETER;
00901   }
00902 
00903   //
00904   // Before starting the Blocking BlockIO operation, push to finish all non-blocking
00905   // BlockIO tasks.
00906   // Delay 100us to simulate the blocking time out checking.
00907   //
00908   while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {
00909     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
00910     AsyncNonBlockingTransferRoutine (NULL, Instance);
00911     gBS->RestoreTPL (OldTpl);  
00912     //
00913     // Stall for 100us.
00914     //
00915     MicroSecondDelay (100);
00916   }
00917 
00918   if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {
00919     //
00920     // Mark the Task to indicate that it has been started.
00921     //
00922     if (Task != NULL) {
00923       Task->IsStart      = TRUE;
00924       Task->RetryTimes   = (UINT32) (DivU64x32(Timeout, 1000) + 1);
00925     }
00926     if (Read) {
00927       Flag = EfiPciIoOperationBusMasterWrite;
00928     } else {
00929       Flag = EfiPciIoOperationBusMasterRead;
00930     }
00931 
00932     //
00933     // Construct command list and command table with pci bus address.
00934     //
00935     MapLength = DataCount;
00936     Status = PciIo->Map (
00937                       PciIo,
00938                       Flag,
00939                       MemoryAddr,
00940                       &MapLength,
00941                       &PhyAddr,
00942                       &Map
00943                       );
00944 
00945     if (EFI_ERROR (Status) || (DataCount != MapLength)) {
00946       return EFI_BAD_BUFFER_SIZE;
00947     }
00948 
00949     if (Task != NULL) {
00950       Task->Map = Map;
00951     }
00952     //
00953     // Package read needed
00954     //
00955     AhciBuildCommandFis (&CFis, AtaCommandBlock);
00956 
00957     ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
00958 
00959     CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
00960     CmdList.AhciCmdW   = Read ? 0 : 1;
00961 
00962     AhciBuildCommand (
00963       PciIo,
00964       AhciRegisters,
00965       Port,
00966       PortMultiplier,
00967       &CFis,
00968       &CmdList,
00969       AtapiCommand,
00970       AtapiCommandLength,
00971       0,
00972       (VOID *)(UINTN)PhyAddr,
00973       DataCount
00974       );
00975 
00976     Status = AhciStartCommand (
00977                PciIo,
00978                Port,
00979                0,
00980                Timeout
00981                );
00982     if (EFI_ERROR (Status)) {
00983       goto Exit;
00984     }
00985   }
00986 
00987   //
00988   // Wait for command compelte
00989   //
00990   FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
00991   Offset      = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
00992   if (Task != NULL) {
00993     //
00994     // For Non-blocking
00995     //
00996     Status = AhciCheckMemSet (
00997                Offset,
00998                EFI_AHCI_FIS_TYPE_MASK,
00999                EFI_AHCI_FIS_REGISTER_D2H,
01000                (UINTN *) (&Task->RetryTimes)
01001                );
01002   } else {
01003     Status = AhciWaitMemSet (
01004                Offset,
01005                EFI_AHCI_FIS_TYPE_MASK,
01006                EFI_AHCI_FIS_REGISTER_D2H,
01007                Timeout
01008                );
01009   }
01010 
01011   if (EFI_ERROR (Status)) {
01012     goto Exit;
01013   }
01014 
01015   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
01016   PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
01017   if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
01018     Status = EFI_DEVICE_ERROR;
01019   }
01020 
01021 Exit:
01022   //
01023   // For Blocking mode, the command should be stopped, the Fis should be disabled
01024   // and the PciIo should be unmapped.
01025   // For non-blocking mode, only when a error is happened (if the return status is 
01026   // EFI_NOT_READY that means the command doesn't finished, try again.), first do the 
01027   // context cleanup, then set the packet's Asb status.
01028   //
01029   if (Task == NULL ||
01030       ((Task != NULL) && (Status != EFI_NOT_READY))
01031      ) {
01032     AhciStopCommand (
01033       PciIo, 
01034       Port,
01035       Timeout
01036       );
01037 
01038     AhciDisableFisReceive (
01039       PciIo, 
01040       Port,
01041       Timeout
01042       );
01043 
01044     PciIo->Unmap (
01045              PciIo,
01046              (Task != NULL) ? Task->Map : Map
01047              );
01048 
01049     if (Task != NULL) {
01050       Task->Packet->Asb->AtaStatus = 0x01;
01051     }
01052   }
01053 
01054   AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);
01055   return Status;
01056 }
01057 
01080 EFI_STATUS
01081 EFIAPI
01082 AhciNonDataTransfer (
01083   IN     EFI_PCI_IO_PROTOCOL           *PciIo,
01084   IN     EFI_AHCI_REGISTERS            *AhciRegisters,
01085   IN     UINT8                         Port,
01086   IN     UINT8                         PortMultiplier,
01087   IN     EFI_AHCI_ATAPI_COMMAND        *AtapiCommand OPTIONAL,
01088   IN     UINT8                         AtapiCommandLength,
01089   IN     EFI_ATA_COMMAND_BLOCK         *AtaCommandBlock,
01090   IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock,
01091   IN     UINT64                        Timeout,
01092   IN     ATA_NONBLOCK_TASK             *Task
01093   )
01094 {
01095   EFI_STATUS                   Status;
01096   UINTN                        FisBaseAddr;
01097   UINTN                        Offset;
01098   UINT32                       PortTfd;
01099   EFI_AHCI_COMMAND_FIS         CFis;
01100   EFI_AHCI_COMMAND_LIST        CmdList;
01101 
01102   //
01103   // Package read needed
01104   //
01105   AhciBuildCommandFis (&CFis, AtaCommandBlock);
01106 
01107   ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
01108 
01109   CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
01110 
01111   AhciBuildCommand (
01112     PciIo,
01113     AhciRegisters,
01114     Port,
01115     PortMultiplier,
01116     &CFis,
01117     &CmdList,
01118     AtapiCommand,
01119     AtapiCommandLength,
01120     0,
01121     NULL,
01122     0
01123     );
01124 
01125   Status = AhciStartCommand (
01126              PciIo,
01127              Port,
01128              0,
01129              Timeout
01130              );
01131   if (EFI_ERROR (Status)) {
01132     goto Exit;
01133   }
01134 
01135   //
01136   // Wait device sends the Response Fis
01137   //
01138   FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
01139   Offset      = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
01140   Status      = AhciWaitMemSet (
01141                   Offset,
01142                   EFI_AHCI_FIS_TYPE_MASK,
01143                   EFI_AHCI_FIS_REGISTER_D2H,
01144                   Timeout
01145                   );
01146 
01147   if (EFI_ERROR (Status)) {
01148     goto Exit;
01149   }
01150 
01151   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
01152   PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
01153   if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
01154     Status = EFI_DEVICE_ERROR;
01155   }
01156 
01157 Exit:
01158   AhciStopCommand (
01159     PciIo,
01160     Port,
01161     Timeout
01162     );
01163 
01164   AhciDisableFisReceive (
01165     PciIo,
01166     Port,
01167     Timeout
01168     );
01169 
01170   AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);
01171 
01172   return Status;
01173 }
01174 
01187 EFI_STATUS
01188 EFIAPI
01189 AhciStopCommand (
01190   IN  EFI_PCI_IO_PROTOCOL       *PciIo,
01191   IN  UINT8                     Port,
01192   IN  UINT64                    Timeout
01193   )
01194 {
01195   UINT32 Offset;
01196   UINT32 Data;
01197 
01198   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
01199   Data   = AhciReadReg (PciIo, Offset);
01200 
01201   if ((Data & (EFI_AHCI_PORT_CMD_ST |  EFI_AHCI_PORT_CMD_CR)) == 0) {
01202     return EFI_SUCCESS;
01203   }
01204 
01205   if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
01206     AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
01207   }
01208 
01209   return AhciWaitMmioSet (
01210            PciIo,
01211            Offset,
01212            EFI_AHCI_PORT_CMD_CR,
01213            0,
01214            Timeout
01215            );
01216 }
01217 
01231 EFI_STATUS
01232 EFIAPI
01233 AhciStartCommand (
01234   IN  EFI_PCI_IO_PROTOCOL       *PciIo,
01235   IN  UINT8                     Port,
01236   IN  UINT8                     CommandSlot,
01237   IN  UINT64                    Timeout
01238   )
01239 {
01240   UINT32     CmdSlotBit;
01241   EFI_STATUS Status;
01242   UINT32     PortStatus;
01243   UINT32     StartCmd;
01244   UINT32     PortTfd;
01245   UINT32     Offset;
01246   UINT32     Capability;
01247 
01248   //
01249   // Collect AHCI controller information
01250   //
01251   Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);
01252 
01253   CmdSlotBit = (UINT32) (1 << CommandSlot);
01254 
01255   AhciClearPortStatus (
01256     PciIo,
01257     Port
01258     );
01259 
01260   Status = AhciEnableFisReceive (
01261              PciIo, 
01262              Port,
01263              Timeout
01264              );
01265 
01266   if (EFI_ERROR (Status)) {
01267     return Status;
01268   }
01269 
01270   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
01271   PortStatus = AhciReadReg (PciIo, Offset);
01272 
01273   StartCmd = 0;
01274   if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
01275     StartCmd = AhciReadReg (PciIo, Offset);
01276     StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;
01277     StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;
01278   }
01279 
01280   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
01281   PortTfd = AhciReadReg (PciIo, Offset);
01282 
01283   if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
01284     if ((Capability & BIT24) != 0) {
01285       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
01286       AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);
01287 
01288       AhciWaitMmioSet (
01289         PciIo,
01290         Offset,
01291         EFI_AHCI_PORT_CMD_CLO,
01292         0,
01293         Timeout
01294         );
01295     }
01296   }
01297 
01298   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
01299   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
01300 
01301   //
01302   // Setting the command
01303   //
01304   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;
01305   AhciAndReg (PciIo, Offset, 0);
01306   AhciOrReg (PciIo, Offset, CmdSlotBit);
01307 
01308   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
01309   AhciAndReg (PciIo, Offset, 0);
01310   AhciOrReg (PciIo, Offset, CmdSlotBit);
01311 
01312   return EFI_SUCCESS;
01313 }
01314 
01327 EFI_STATUS
01328 EFIAPI
01329 AhciPortReset (
01330   IN  EFI_PCI_IO_PROTOCOL       *PciIo,
01331   IN  UINT8                     Port,
01332   IN  UINT64                    Timeout
01333   )
01334 {
01335   EFI_STATUS      Status;
01336   UINT32          Offset;
01337 
01338   AhciClearPortStatus (PciIo, Port);
01339 
01340   AhciStopCommand (PciIo, Port, Timeout);
01341 
01342   AhciDisableFisReceive (PciIo, Port, Timeout);
01343 
01344   AhciEnableFisReceive (PciIo, Port, Timeout);
01345 
01346   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
01347 
01348   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);
01349 
01350   //
01351   // wait 5 millisecond before de-assert DET
01352   //
01353   MicroSecondDelay (5000);
01354 
01355   AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);
01356 
01357   //
01358   // wait 5 millisecond before de-assert DET
01359   //
01360   MicroSecondDelay (5000);
01361 
01362   //
01363   // Wait for communication to be re-established
01364   //
01365   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
01366   Status = AhciWaitMmioSet (
01367              PciIo,
01368              Offset,
01369              EFI_AHCI_PORT_SSTS_DET_MASK,
01370              EFI_AHCI_PORT_SSTS_DET_PCE,
01371              Timeout
01372              );
01373 
01374   if (EFI_ERROR (Status)) {
01375     return Status;
01376   }
01377 
01378   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
01379   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);
01380 
01381   return EFI_SUCCESS;
01382 }
01383 
01395 EFI_STATUS
01396 EFIAPI
01397 AhciReset (
01398   IN  EFI_PCI_IO_PROTOCOL       *PciIo,
01399   IN  UINT64                    Timeout
01400   )    
01401 {
01402   UINT32                 Delay;
01403   UINT32                 Value;
01404 
01405   AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
01406 
01407   AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
01408 
01409   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
01410 
01411   do {
01412     Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);
01413 
01414     if ((Value & EFI_AHCI_GHC_RESET) == 0) {
01415       break;
01416     }
01417 
01418     //
01419     // Stall for 100 microseconds.
01420     //
01421     MicroSecondDelay(100);
01422 
01423     Delay--;
01424   } while (Delay > 0);
01425 
01426   if (Delay == 0) {
01427     return EFI_TIMEOUT;
01428   }
01429 
01430   return EFI_SUCCESS;
01431 }
01432 
01446 EFI_STATUS
01447 EFIAPI
01448 AhciAtaSmartReturnStatusCheck (
01449   IN EFI_PCI_IO_PROTOCOL         *PciIo,
01450   IN EFI_AHCI_REGISTERS          *AhciRegisters,
01451   IN UINT8                       Port,
01452   IN UINT8                       PortMultiplier,
01453   IN OUT EFI_ATA_STATUS_BLOCK    *AtaStatusBlock
01454   )
01455 {
01456   EFI_STATUS              Status;
01457   EFI_ATA_COMMAND_BLOCK   AtaCommandBlock;
01458   UINT8                   LBAMid;
01459   UINT8                   LBAHigh;
01460   UINTN                   FisBaseAddr;
01461   UINT32                  Value;
01462 
01463   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
01464 
01465   AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;
01466   AtaCommandBlock.AtaFeatures     = ATA_SMART_RETURN_STATUS;
01467   AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;
01468   AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
01469 
01470   //
01471   // Send S.M.A.R.T Read Return Status command to device
01472   //
01473   Status = AhciNonDataTransfer (
01474              PciIo,
01475              AhciRegisters,
01476              (UINT8)Port,
01477              (UINT8)PortMultiplier,
01478              NULL,
01479              0,
01480              &AtaCommandBlock,
01481              AtaStatusBlock,
01482              ATA_ATAPI_TIMEOUT,
01483              NULL
01484              );
01485 
01486   if (EFI_ERROR (Status)) {
01487     return EFI_DEVICE_ERROR;
01488   }
01489 
01490   FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
01491 
01492   Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);
01493 
01494   if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {
01495     LBAMid  = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];
01496     LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];
01497 
01498     if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
01499       //
01500       // The threshold exceeded condition is not detected by the device
01501       //
01502       DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
01503 
01504     } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {
01505       //
01506       // The threshold exceeded condition is detected by the device
01507       //
01508       DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));
01509     }
01510   }
01511 
01512   return EFI_SUCCESS;
01513 }
01514 
01526 VOID
01527 EFIAPI
01528 AhciAtaSmartSupport (
01529   IN EFI_PCI_IO_PROTOCOL           *PciIo,
01530   IN EFI_AHCI_REGISTERS            *AhciRegisters,
01531   IN UINT8                         Port,
01532   IN UINT8                         PortMultiplier,
01533   IN EFI_IDENTIFY_DATA             *IdentifyData,
01534   IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock
01535   )
01536 {
01537   EFI_STATUS               Status;
01538   EFI_ATA_COMMAND_BLOCK    AtaCommandBlock;
01539 
01540   //
01541   // Detect if the device supports S.M.A.R.T.
01542   //
01543   if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
01544     //
01545     // S.M.A.R.T is not supported by the device
01546     //
01547     DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n", 
01548             Port, PortMultiplier));
01549   } else {
01550     //
01551     // Check if the feature is enabled. If not, then enable S.M.A.R.T.
01552     //
01553     if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {
01554       ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
01555 
01556       AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;
01557       AtaCommandBlock.AtaFeatures     = ATA_SMART_ENABLE_OPERATION;
01558       AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;
01559       AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
01560 
01561       //
01562       // Send S.M.A.R.T Enable command to device
01563       //
01564       Status = AhciNonDataTransfer (
01565                  PciIo,
01566                  AhciRegisters,
01567                  (UINT8)Port,
01568                  (UINT8)PortMultiplier,
01569                  NULL,
01570                  0,
01571                  &AtaCommandBlock,
01572                  AtaStatusBlock,
01573                  ATA_ATAPI_TIMEOUT,
01574                  NULL
01575                  );
01576 
01577 
01578       if (!EFI_ERROR (Status)) {
01579         //
01580         // Send S.M.A.R.T AutoSave command to device
01581         //
01582         ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
01583 
01584         AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;
01585         AtaCommandBlock.AtaFeatures     = 0xD2;
01586         AtaCommandBlock.AtaSectorCount  = 0xF1;
01587         AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;
01588         AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
01589 
01590         Status = AhciNonDataTransfer (
01591                    PciIo,
01592                    AhciRegisters,
01593                    (UINT8)Port,
01594                    (UINT8)PortMultiplier,
01595                    NULL,
01596                    0,
01597                    &AtaCommandBlock,
01598                    AtaStatusBlock,
01599                    ATA_ATAPI_TIMEOUT,
01600                    NULL
01601                    );
01602 
01603         if (!EFI_ERROR (Status)) {
01604           Status = AhciAtaSmartReturnStatusCheck (
01605                      PciIo,
01606                      AhciRegisters,
01607                      (UINT8)Port,
01608                      (UINT8)PortMultiplier,
01609                      AtaStatusBlock
01610                      );
01611         }
01612       }
01613     }
01614     DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
01615             Port, PortMultiplier));
01616   }
01617 
01618   return ;
01619 }
01620 
01636 EFI_STATUS
01637 EFIAPI
01638 AhciIdentify (
01639   IN EFI_PCI_IO_PROTOCOL      *PciIo,
01640   IN EFI_AHCI_REGISTERS       *AhciRegisters,
01641   IN UINT8                    Port,
01642   IN UINT8                    PortMultiplier,
01643   IN OUT EFI_IDENTIFY_DATA    *Buffer  
01644   )
01645 {
01646   EFI_STATUS                   Status;
01647   EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;
01648   EFI_ATA_STATUS_BLOCK         AtaStatusBlock;
01649 
01650   if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {
01651     return EFI_INVALID_PARAMETER;
01652   }
01653 
01654   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
01655   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
01656 
01657   AtaCommandBlock.AtaCommand     = ATA_CMD_IDENTIFY_DRIVE;
01658   AtaCommandBlock.AtaSectorCount = 1;
01659 
01660   Status = AhciPioTransfer (
01661              PciIo,
01662              AhciRegisters,
01663              Port,
01664              PortMultiplier,
01665              NULL,
01666              0,
01667              TRUE,
01668              &AtaCommandBlock,
01669              &AtaStatusBlock,
01670              Buffer,
01671              sizeof (EFI_IDENTIFY_DATA),
01672              ATA_ATAPI_TIMEOUT, 
01673              NULL
01674              );
01675 
01676   return Status;
01677 }
01678 
01694 EFI_STATUS
01695 EFIAPI
01696 AhciIdentifyPacket (
01697   IN EFI_PCI_IO_PROTOCOL      *PciIo,
01698   IN EFI_AHCI_REGISTERS       *AhciRegisters,
01699   IN UINT8                    Port,
01700   IN UINT8                    PortMultiplier,
01701   IN OUT EFI_IDENTIFY_DATA    *Buffer  
01702   )
01703 {
01704   EFI_STATUS                   Status;
01705   EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;
01706   EFI_ATA_STATUS_BLOCK         AtaStatusBlock;
01707 
01708   if (PciIo == NULL || AhciRegisters == NULL) {
01709     return EFI_INVALID_PARAMETER;
01710   }
01711 
01712   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
01713   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
01714 
01715   AtaCommandBlock.AtaCommand     = ATA_CMD_IDENTIFY_DEVICE;
01716   AtaCommandBlock.AtaSectorCount = 1;
01717 
01718   Status = AhciPioTransfer (
01719              PciIo,
01720              AhciRegisters,
01721              Port,
01722              PortMultiplier,
01723              NULL,
01724              0,
01725              TRUE,
01726              &AtaCommandBlock,
01727              &AtaStatusBlock,
01728              Buffer,
01729              sizeof (EFI_IDENTIFY_DATA),
01730              ATA_ATAPI_TIMEOUT,
01731              NULL
01732              );
01733 
01734   return Status;
01735 }
01736 
01753 EFI_STATUS
01754 EFIAPI
01755 AhciDeviceSetFeature (
01756   IN EFI_PCI_IO_PROTOCOL    *PciIo,
01757   IN EFI_AHCI_REGISTERS     *AhciRegisters,
01758   IN UINT8                  Port,
01759   IN UINT8                  PortMultiplier,
01760   IN UINT16                 Feature,
01761   IN UINT32                 FeatureSpecificData
01762   )
01763 {
01764   EFI_STATUS               Status;
01765   EFI_ATA_COMMAND_BLOCK    AtaCommandBlock;
01766   EFI_ATA_STATUS_BLOCK     AtaStatusBlock;
01767 
01768   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
01769   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
01770 
01771   AtaCommandBlock.AtaCommand      = ATA_CMD_SET_FEATURES;
01772   AtaCommandBlock.AtaFeatures     = (UINT8) Feature;
01773   AtaCommandBlock.AtaFeaturesExp  = (UINT8) (Feature >> 8);
01774   AtaCommandBlock.AtaSectorCount  = (UINT8) FeatureSpecificData;
01775   AtaCommandBlock.AtaSectorNumber = (UINT8) (FeatureSpecificData >> 8);
01776   AtaCommandBlock.AtaCylinderLow  = (UINT8) (FeatureSpecificData >> 16);
01777   AtaCommandBlock.AtaCylinderHigh = (UINT8) (FeatureSpecificData >> 24);
01778 
01779   Status = AhciNonDataTransfer (
01780              PciIo,
01781              AhciRegisters,
01782              (UINT8)Port,
01783              (UINT8)PortMultiplier,
01784              NULL,
01785              0,
01786              &AtaCommandBlock,
01787              &AtaStatusBlock,
01788              ATA_ATAPI_TIMEOUT, 
01789              NULL
01790              );
01791 
01792   return Status;
01793 }
01794 
01810 EFI_STATUS
01811 EFIAPI
01812 AhciPacketCommandExecute (
01813   IN  EFI_PCI_IO_PROTOCOL                           *PciIo,
01814   IN  EFI_AHCI_REGISTERS                            *AhciRegisters,
01815   IN  UINT8                                         Port,
01816   IN  UINT8                                         PortMultiplier,
01817   IN  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
01818   )
01819 {
01820   EFI_STATUS                   Status;
01821   VOID                         *Buffer;
01822   UINT32                       Length;
01823   EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;
01824   EFI_ATA_STATUS_BLOCK         AtaStatusBlock;
01825   BOOLEAN                      Read;
01826 
01827   if (Packet == NULL || Packet->Cdb == NULL) {
01828     return EFI_INVALID_PARAMETER;
01829   }
01830 
01831   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
01832   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
01833   AtaCommandBlock.AtaCommand      = ATA_CMD_PACKET;
01834   //
01835   // No OVL; No DMA
01836   //
01837   AtaCommandBlock.AtaFeatures     = 0x00;
01838   //
01839   // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
01840   // determine how many data should be transferred.
01841   //
01842   AtaCommandBlock.AtaCylinderLow  = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);
01843   AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);
01844 
01845   if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
01846     Buffer = Packet->InDataBuffer;
01847     Length = Packet->InTransferLength;
01848     Read = TRUE;
01849   } else {
01850     Buffer = Packet->OutDataBuffer;
01851     Length = Packet->OutTransferLength;
01852     Read = FALSE;
01853   }
01854 
01855   if (Length == 0) {
01856     Status = AhciNonDataTransfer (
01857                PciIo,
01858                AhciRegisters,
01859                Port,
01860                PortMultiplier,
01861                Packet->Cdb,
01862                Packet->CdbLength,
01863                &AtaCommandBlock,
01864                &AtaStatusBlock,
01865                Packet->Timeout, 
01866                NULL
01867                );
01868   } else {
01869     Status = AhciPioTransfer (
01870                PciIo,
01871                AhciRegisters,
01872                Port,
01873                PortMultiplier,
01874                Packet->Cdb,
01875                Packet->CdbLength,
01876                Read,
01877                &AtaCommandBlock,
01878                &AtaStatusBlock,
01879                Buffer,
01880                Length,
01881                Packet->Timeout, 
01882                NULL
01883                );
01884   }
01885   return Status;
01886 }
01887 
01895 EFI_STATUS
01896 EFIAPI
01897 AhciCreateTransferDescriptor (
01898   IN     EFI_PCI_IO_PROTOCOL    *PciIo,
01899   IN OUT EFI_AHCI_REGISTERS     *AhciRegisters
01900   )
01901 {
01902   EFI_STATUS            Status;
01903   UINTN                 Bytes;
01904   VOID                  *Buffer;
01905 
01906   UINT32                Capability;
01907   UINT8                 MaxPortNumber;
01908   UINT8                 MaxCommandSlotNumber;
01909   BOOLEAN               Support64Bit;
01910   UINT64                MaxReceiveFisSize;
01911   UINT64                MaxCommandListSize;
01912   UINT64                MaxCommandTableSize;
01913   EFI_PHYSICAL_ADDRESS  AhciRFisPciAddr;
01914   EFI_PHYSICAL_ADDRESS  AhciCmdListPciAddr;
01915   EFI_PHYSICAL_ADDRESS  AhciCommandTablePciAddr;
01916 
01917   Buffer = NULL;
01918   //
01919   // Collect AHCI controller information
01920   //
01921   Capability           = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);
01922   MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);
01923   //
01924   // Get the number of command slots per port supported by this HBA.
01925   //
01926   MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);
01927   Support64Bit         = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);
01928 
01929   MaxReceiveFisSize    = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);
01930   Status = PciIo->AllocateBuffer (
01931                     PciIo,
01932                     AllocateAnyPages,
01933                     EfiBootServicesData,
01934                     EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),
01935                     &Buffer,
01936                     0
01937                     );
01938 
01939   if (EFI_ERROR (Status)) {
01940     return EFI_OUT_OF_RESOURCES;
01941   }
01942 
01943   ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);
01944 
01945   AhciRegisters->AhciRFis          = Buffer;
01946   AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;
01947   Bytes  = (UINTN)MaxReceiveFisSize;
01948 
01949   Status = PciIo->Map (
01950                     PciIo,
01951                     EfiPciIoOperationBusMasterCommonBuffer,
01952                     Buffer,
01953                     &Bytes,
01954                     &AhciRFisPciAddr,
01955                     &AhciRegisters->MapRFis
01956                     );
01957 
01958   if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {
01959     //
01960     // Map error or unable to map the whole RFis buffer into a contiguous region. 
01961     //
01962     Status = EFI_OUT_OF_RESOURCES;
01963     goto Error6;
01964   }
01965 
01966   if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {
01967     //
01968     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
01969     //
01970     Status = EFI_DEVICE_ERROR;
01971     goto Error5;
01972   }
01973   AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;
01974 
01975   //
01976   // Allocate memory for command list
01977   // Note that the implemenation is a single task model which only use a command list for all ports.
01978   //
01979   Buffer = NULL;
01980   MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);
01981   Status = PciIo->AllocateBuffer (
01982                     PciIo,
01983                     AllocateAnyPages,
01984                     EfiBootServicesData,
01985                     EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),
01986                     &Buffer,
01987                     0
01988                     );
01989 
01990   if (EFI_ERROR (Status)) {
01991     //
01992     // Free mapped resource. 
01993     //
01994     Status = EFI_OUT_OF_RESOURCES;
01995     goto Error5;
01996   }
01997 
01998   ZeroMem (Buffer, (UINTN)MaxCommandListSize);
01999 
02000   AhciRegisters->AhciCmdList        = Buffer;
02001   AhciRegisters->MaxCommandListSize = MaxCommandListSize;
02002   Bytes  = (UINTN)MaxCommandListSize;
02003 
02004   Status = PciIo->Map (
02005                     PciIo,
02006                     EfiPciIoOperationBusMasterCommonBuffer,
02007                     Buffer,
02008                     &Bytes,
02009                     &AhciCmdListPciAddr,
02010                     &AhciRegisters->MapCmdList
02011                     );
02012 
02013   if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {
02014     //
02015     // Map error or unable to map the whole cmd list buffer into a contiguous region.
02016     //
02017     Status = EFI_OUT_OF_RESOURCES;
02018     goto Error4;
02019   }
02020 
02021   if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {
02022     //
02023     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
02024     //
02025     Status = EFI_DEVICE_ERROR;
02026     goto Error3;
02027   }
02028   AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;
02029 
02030   //
02031   // Allocate memory for command table
02032   // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
02033   //
02034   Buffer = NULL;
02035   MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);
02036 
02037   Status = PciIo->AllocateBuffer (
02038                     PciIo,
02039                     AllocateAnyPages,
02040                     EfiBootServicesData,
02041                     EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),
02042                     &Buffer,
02043                     0
02044                     );
02045 
02046   if (EFI_ERROR (Status)) {
02047     //
02048     // Free mapped resource. 
02049     //
02050     Status = EFI_OUT_OF_RESOURCES;
02051     goto Error3;
02052   }
02053 
02054   ZeroMem (Buffer, (UINTN)MaxCommandTableSize);
02055 
02056   AhciRegisters->AhciCommandTable    = Buffer;
02057   AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;
02058   Bytes  = (UINTN)MaxCommandTableSize;
02059 
02060   Status = PciIo->Map (
02061                     PciIo,
02062                     EfiPciIoOperationBusMasterCommonBuffer,
02063                     Buffer,
02064                     &Bytes,
02065                     &AhciCommandTablePciAddr,
02066                     &AhciRegisters->MapCommandTable
02067                     );
02068 
02069   if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {
02070     //
02071     // Map error or unable to map the whole cmd list buffer into a contiguous region.
02072     //
02073     Status = EFI_OUT_OF_RESOURCES;
02074     goto Error2;
02075   }
02076 
02077   if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {
02078     //
02079     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
02080     //
02081     Status = EFI_DEVICE_ERROR;
02082     goto Error1;
02083   }
02084   AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;
02085 
02086   return EFI_SUCCESS;
02087   //
02088   // Map error or unable to map the whole CmdList buffer into a contiguous region. 
02089   //
02090 Error1:
02091   PciIo->Unmap (
02092            PciIo,
02093            AhciRegisters->MapCommandTable
02094            );
02095 Error2:
02096   PciIo->FreeBuffer (
02097            PciIo,
02098            EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),
02099            AhciRegisters->AhciCommandTable
02100            );
02101 Error3:
02102   PciIo->Unmap (
02103            PciIo,
02104            AhciRegisters->MapCmdList
02105            );
02106 Error4:
02107   PciIo->FreeBuffer (
02108            PciIo,
02109            EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),
02110            AhciRegisters->AhciCmdList
02111            );
02112 Error5:
02113   PciIo->Unmap (
02114            PciIo,
02115            AhciRegisters->MapRFis
02116            );
02117 Error6:
02118   PciIo->FreeBuffer (
02119            PciIo,
02120            EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),
02121            AhciRegisters->AhciRFis
02122            );
02123 
02124   return Status;
02125 }
02126 
02135 EFI_STATUS
02136 EFIAPI
02137 AhciModeInitialization (
02138   IN  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance
02139   )
02140 {
02141   EFI_STATUS                       Status;
02142   EFI_PCI_IO_PROTOCOL              *PciIo;
02143   EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
02144   UINT32                           Capability;
02145   UINT8                            MaxPortNumber;
02146   UINT32                           PortImplementBitMap;
02147 
02148   EFI_AHCI_REGISTERS               *AhciRegisters;
02149 
02150   UINT8                            Port;
02151   DATA_64                          Data64;
02152   UINT32                           Offset;
02153   UINT32                           Data;
02154   EFI_IDENTIFY_DATA                Buffer;
02155   EFI_ATA_DEVICE_TYPE              DeviceType;
02156   EFI_ATA_COLLECTIVE_MODE          *SupportedModes;
02157   EFI_ATA_TRANSFER_MODE            TransferMode;
02158   UINT32                           PhyDetectDelay;
02159 
02160   if (Instance == NULL) {
02161     return EFI_INVALID_PARAMETER;
02162   }
02163 
02164   PciIo   = Instance->PciIo;
02165   IdeInit = Instance->IdeControllerInit;
02166 
02167   Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT); 
02168 
02169   if (EFI_ERROR (Status)) {
02170     return EFI_DEVICE_ERROR;
02171   }
02172 
02173   //
02174   // Enable AE before accessing any AHCI registers
02175   //
02176   AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
02177 
02178   //
02179   // Collect AHCI controller information
02180   //
02181   Capability           = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);
02182 
02183   //
02184   // Get the number of command slots per port supported by this HBA.
02185   //
02186   MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);
02187 
02188   //
02189   // Get the bit map of those ports exposed by this HBA.
02190   // It indicates which ports that the HBA supports are available for software to use. 
02191   //
02192   PortImplementBitMap  = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);
02193   
02194   AhciRegisters = &Instance->AhciRegisters;
02195   Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);
02196 
02197   if (EFI_ERROR (Status)) {
02198     return EFI_OUT_OF_RESOURCES;
02199   }
02200 
02201   for (Port = 0; Port < MaxPortNumber; Port ++) {  
02202     if ((PortImplementBitMap & (BIT0 << Port)) != 0) {
02203       IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);
02204 
02205       //
02206       // Initialize FIS Base Address Register and Command List Base Address Register for use.
02207       //
02208       Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
02209       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
02210       AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
02211       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
02212       AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
02213 
02214       Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);
02215       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
02216       AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
02217       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
02218       AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
02219 
02220       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
02221       Data = AhciReadReg (PciIo, Offset);
02222       if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
02223         AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);
02224       }
02225 
02226       if ((Capability & EFI_AHCI_CAP_SSS) != 0) {
02227         AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);
02228       }
02229 
02230       //
02231       // Disable aggressive power management.
02232       //
02233       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
02234       AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
02235       //
02236       // Disable the reporting of the corresponding interrupt to system software.
02237       //
02238       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
02239       AhciAndReg (PciIo, Offset, 0);
02240 
02241       //
02242       // Now inform the IDE Controller Init Module.
02243       //
02244       IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);
02245 
02246       //
02247       // Enable FIS Receive DMA engine for the first D2H FIS.
02248       //
02249       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
02250       AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);
02251       Status = AhciWaitMmioSet (
02252                  PciIo, 
02253                  Offset,
02254                  EFI_AHCI_PORT_CMD_FR,
02255                  EFI_AHCI_PORT_CMD_FR,
02256                  EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT
02257                  );
02258       if (EFI_ERROR (Status)) {
02259         continue;
02260       }
02261 
02262       //
02263       // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.
02264       // It's the requirment from SATA1.0a spec section 5.2.
02265       //
02266       PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;
02267       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
02268       do {
02269         Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
02270         if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {
02271           break;
02272         }
02273 
02274         MicroSecondDelay (1000);
02275         PhyDetectDelay--;
02276       } while (PhyDetectDelay > 0);
02277 
02278       if (PhyDetectDelay == 0) {
02279         //
02280         // No device detected at this port.
02281         //
02282         continue;
02283       }
02284 
02285       //
02286       // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
02287       // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
02288       //
02289       PhyDetectDelay = 16 * 1000;
02290       do {
02291         Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
02292         if (AhciReadReg(PciIo, Offset) != 0) {
02293           AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));
02294         }
02295         Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
02296 
02297         Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;
02298         if (Data == 0) {
02299           break;
02300         }
02301 
02302         MicroSecondDelay (1000);
02303         PhyDetectDelay--;
02304       } while (PhyDetectDelay > 0);
02305       
02306       if (PhyDetectDelay == 0) {
02307         continue;
02308       }
02309 
02310       //
02311       // When the first D2H register FIS is received, the content of PxSIG register is updated.
02312       //
02313       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
02314       Status = AhciWaitMmioSet (
02315                  PciIo, 
02316                  Offset,
02317                  0x0000FFFF,
02318                  0x00000101,
02319                  EFI_TIMER_PERIOD_SECONDS(16)
02320                  );
02321       if (EFI_ERROR (Status)) {
02322         continue;
02323       }
02324 
02325       Data = AhciReadReg (PciIo, Offset);
02326       if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {
02327         Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);
02328 
02329         if (EFI_ERROR (Status)) {
02330           continue;
02331         }
02332 
02333         DeviceType = EfiIdeCdrom;
02334       } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {
02335         Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);
02336 
02337         if (EFI_ERROR (Status)) {
02338           REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));
02339           continue;
02340         }
02341 
02342         DeviceType = EfiIdeHarddisk;
02343       } else {
02344         continue;
02345       }
02346       DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", 
02347               Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
02348 
02349       //
02350       // If the device is a hard disk, then try to enable S.M.A.R.T feature
02351       //
02352       if (DeviceType == EfiIdeHarddisk) {
02353         AhciAtaSmartSupport (
02354           PciIo,
02355           AhciRegisters,
02356           Port,
02357           0,
02358           &Buffer,
02359           NULL
02360           );
02361       }
02362 
02363       //
02364       // Submit identify data to IDE controller init driver
02365       //
02366       IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);
02367 
02368       //
02369       // Now start to config ide device parameter and transfer mode.
02370       //
02371       Status = IdeInit->CalculateMode (
02372                           IdeInit,
02373                           Port,
02374                           0,
02375                           &SupportedModes
02376                           );
02377       if (EFI_ERROR (Status)) {
02378         DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));
02379         continue;
02380       }
02381 
02382       //
02383       // Set best supported PIO mode on this IDE device
02384       //
02385       if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {
02386         TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;
02387       } else {
02388         TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;
02389       }
02390 
02391       TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
02392 
02393       //
02394       // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
02395       // be set together. Only one DMA mode can be set to a device. If setting
02396       // DMA mode operation fails, we can continue moving on because we only use
02397       // PIO mode at boot time. DMA modes are used by certain kind of OS booting
02398       //
02399       if (SupportedModes->UdmaMode.Valid) {
02400         TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;
02401         TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
02402       } else if (SupportedModes->MultiWordDmaMode.Valid) {
02403         TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
02404         TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;  
02405       }
02406 
02407       Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));
02408       if (EFI_ERROR (Status)) {
02409         DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
02410         continue;
02411       }
02412 
02413       //
02414       // Found a ATA or ATAPI device, add it into the device list.
02415       //
02416       CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);
02417       if (DeviceType == EfiIdeHarddisk) {
02418         REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));
02419       }
02420     }
02421   }
02422 
02423   return EFI_SUCCESS;
02424 }
02425 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines