/** @file\r
The file for AHCI mode of ATA host controller.\r
\r
- Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
@param PortMultiplier The port multiplier port number.\r
@param Feature The data to send Feature register.\r
@param FeatureSpecificData The specific data for SET FEATURE cmd.\r
+ @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.\r
\r
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
@retval EFI_TIMEOUT The operation is time out.\r
IN UINT8 Port,\r
IN UINT8 PortMultiplier,\r
IN UINT16 Feature,\r
- IN UINT32 FeatureSpecificData\r
+ IN UINT32 FeatureSpecificData,\r
+ IN UINT64 Timeout\r
)\r
{\r
EFI_STATUS Status;\r
0,\r
&AtaCommandBlock,\r
&AtaStatusBlock,\r
- ATA_ATAPI_TIMEOUT,\r
+ Timeout,\r
NULL\r
);\r
\r
return Status;\r
}\r
\r
+\r
+/**\r
+ Spin-up disk if IDD was incomplete or PUIS feature is enabled\r
+\r
+ @param PciIo The PCI IO protocol instance.\r
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The multiplier of port.\r
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
+\r
+**/\r
+EFI_STATUS\r
+AhciSpinUpDisk (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_AHCI_REGISTERS *AhciRegisters,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN OUT EFI_IDENTIFY_DATA *IdentifyData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
+ UINT8 Buffer[512];\r
+\r
+ if (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE) {\r
+ //\r
+ // Use SET_FEATURE subcommand to spin up the device.\r
+ //\r
+ Status = AhciDeviceSetFeature (\r
+ PciIo, AhciRegisters, Port, PortMultiplier,\r
+ ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP, 0x00, ATA_SPINUP_TIMEOUT\r
+ );\r
+ DEBUG ((DEBUG_INFO, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+ Port, PortMultiplier, Status));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ ASSERT (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE);\r
+\r
+ //\r
+ // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported\r
+ //\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ //\r
+ // Perform READ SECTORS PIO Data-In command to Read LBA 0\r
+ //\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_READ_SECTORS;\r
+ AtaCommandBlock.AtaSectorCount = 0x1;\r
+\r
+ Status = AhciPioTransfer (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ PortMultiplier,\r
+ NULL,\r
+ 0,\r
+ TRUE,\r
+ &AtaCommandBlock,\r
+ &AtaStatusBlock,\r
+ &Buffer,\r
+ sizeof (Buffer),\r
+ ATA_SPINUP_TIMEOUT,\r
+ NULL\r
+ );\r
+ DEBUG ((DEBUG_INFO, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+ Port, PortMultiplier, Status));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Read the complete IDENTIFY DEVICE data.\r
+ //\r
+ ZeroMem (IdentifyData, sizeof (*IdentifyData));\r
+ Status = AhciIdentify (PciIo, AhciRegisters, Port, PortMultiplier, IdentifyData);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+ Port, PortMultiplier, Status));\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
+ IdentifyData->AtaData.config, IdentifyData->AtaData.specific_config,\r
+ IdentifyData->AtaData.command_set_supported_83, IdentifyData->AtaData.command_set_feature_enb_86));\r
+ //\r
+ // Check if IDD is incomplete\r
+ //\r
+ if ((IdentifyData->AtaData.config & BIT2) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Initialize ATA host controller at AHCI mode.\r
\r
continue;\r
}\r
\r
+ DEBUG ((\r
+ DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
+ Buffer.AtaData.config, Buffer.AtaData.specific_config,\r
+ Buffer.AtaData.command_set_supported_83, Buffer.AtaData.command_set_feature_enb_86\r
+ ));\r
+ if ((Buffer.AtaData.config & BIT2) != 0) {\r
+ //\r
+ // SpinUp disk if device reported incomplete IDENTIFY DEVICE.\r
+ //\r
+ Status = AhciSpinUpDisk (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ 0,\r
+ &Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Spin up standby device failed - %r\n", Status));\r
+ continue;\r
+ }\r
+ }\r
+\r
DeviceType = EfiIdeHarddisk;\r
} else {\r
continue;\r
TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
}\r
\r
- Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode), ATA_ATAPI_TIMEOUT);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
continue;\r