/** @file\r
SCSI disk driver that layers on every SCSI IO protocol in the system.\r
\r
-Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php\r
\r
#include "ScsiDisk.h"\r
\r
-\r
EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {\r
ScsiDiskDriverBindingSupported,\r
ScsiDiskDriverBindingStart,\r
NULL\r
};\r
\r
+EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {\r
+ EFI_DISK_INFO_SCSI_INTERFACE_GUID,\r
+ ScsiDiskInfoInquiry,\r
+ ScsiDiskInfoIdentify,\r
+ ScsiDiskInfoSenseData,\r
+ ScsiDiskInfoWhichIde\r
+};\r
\r
/**\r
The user Entry Point for module ScsiDisk.\r
//\r
Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);\r
if (!EFI_ERROR (Status)) {\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &Controller,\r
- &gEfiBlockIoProtocolGuid,\r
- &ScsiDiskDevice->BlkIo,\r
- NULL\r
- );\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- FreePool (ScsiDiskDevice->SenseData);\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiScsiIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
- FreePool (ScsiDiskDevice);\r
- return Status;\r
+ //\r
+ // Determine if Block IO should be produced on this controller handle\r
+ //\r
+ if (DetermineInstallBlockIo(Controller)) {\r
+ InitializeInstallDiskInfo(ScsiDiskDevice, Controller);\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &ScsiDiskDevice->DiskInfo,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ ScsiDiskDevice->ControllerNameTable = NULL;\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gScsiDiskComponentName.SupportedLanguages,\r
+ &ScsiDiskDevice->ControllerNameTable,\r
+ L"SCSI Disk Device",\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gScsiDiskComponentName2.SupportedLanguages,\r
+ &ScsiDiskDevice->ControllerNameTable,\r
+ L"SCSI Disk Device",\r
+ FALSE\r
+ );\r
+ return EFI_SUCCESS;\r
+ }\r
+ } \r
}\r
\r
- ScsiDiskDevice->ControllerNameTable = NULL;\r
- AddUnicodeString2 (\r
- "eng",\r
- gScsiDiskComponentName.SupportedLanguages,\r
- &ScsiDiskDevice->ControllerNameTable,\r
- L"SCSI Disk Device",\r
- TRUE\r
- );\r
- AddUnicodeString2 (\r
- "en",\r
- gScsiDiskComponentName2.SupportedLanguages,\r
- &ScsiDiskDevice->ControllerNameTable,\r
- L"SCSI Disk Device",\r
- FALSE\r
- );\r
-\r
-\r
- return EFI_SUCCESS;\r
-\r
+ gBS->FreePool (ScsiDiskDevice->SenseData);\r
+ gBS->FreePool (ScsiDiskDevice);\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiScsiIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\r
+ \r
}\r
\r
\r
}\r
\r
ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);\r
- Status = gBS->UninstallProtocolInterface (\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
Controller,\r
&gEfiBlockIoProtocolGuid,\r
- &ScsiDiskDevice->BlkIo\r
+ &ScsiDiskDevice->BlkIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &ScsiDiskDevice->DiskInfo,\r
+ NULL\r
);\r
if (!EFI_ERROR (Status)) {\r
gBS->CloseProtocol (\r
@retval EFI_SUCCESS The device was reset.\r
@retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
not be reset.\r
- @return EFI_STATUS is retured from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
+ @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
\r
**/\r
EFI_STATUS\r
\r
\r
/**\r
- Dectect Device and read out capacity ,if error occurs, parse the sense key.\r
+ Detect Device and read out capacity ,if error occurs, parse the sense key.\r
\r
@param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
@param MustReadCapacity The flag about reading device capacity\r
}\r
\r
//\r
- // if goes here, meant SubmitInquiryCommand() failed.\r
+ // if goes here, meant ScsiInquiryCommand() failed.\r
// if ScsiDiskRequestSenseKeys() succeeds at last,\r
- // better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)\r
+ // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)\r
//\r
MaxRetry = 3;\r
for (Index = 0; Index < MaxRetry; Index++) {\r
}\r
\r
/**\r
- To test deivice.\r
+ To test device.\r
\r
When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;\r
When Test Unit Ready command encounters any error caused by host adapter or\r
OUT UINTN *NumberOfSenseKeys\r
)\r
{\r
- EFI_SCSI_DISK_CAPACITY_DATA CapacityData;\r
- UINT32 DataLength;\r
- UINT8 HostAdapterStatus;\r
- UINT8 TargetStatus;\r
- EFI_STATUS CommandStatus;\r
- EFI_STATUS Status;\r
- UINT8 Index;\r
- UINT8 MaxRetry;\r
- UINT8 SenseDataLength;\r
-\r
- SenseDataLength = 0;\r
- ZeroMem (&CapacityData, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
- DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
+ UINT8 HostAdapterStatus;\r
+ UINT8 TargetStatus;\r
+ EFI_STATUS CommandStatus;\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ UINT8 MaxRetry;\r
+ UINT8 SenseDataLength;\r
+ UINT32 DataLength10;\r
+ UINT32 DataLength16;\r
+ EFI_SCSI_DISK_CAPACITY_DATA CapacityData10;\r
+ EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16;\r
+\r
+\r
+ SenseDataLength = 0;\r
+ DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
+ DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
+ ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
+ ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
\r
*NumberOfSenseKeys = 0;\r
*NeedRetry = FALSE;\r
+\r
//\r
- // submit Read Capacity Command. in this call,not request sense data\r
+ // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh, \r
+ // 16 byte command should be used to access large hard disk >2TB\r
//\r
CommandStatus = ScsiReadCapacityCommand (\r
ScsiDiskDevice->ScsiIo,\r
- EFI_TIMER_PERIOD_SECONDS (1),\r
+ EFI_TIMER_PERIOD_SECONDS(1),\r
NULL,\r
&SenseDataLength,\r
&HostAdapterStatus,\r
&TargetStatus,\r
- (VOID *) &CapacityData,\r
- &DataLength,\r
+ (VOID *) &CapacityData10,\r
+ &DataLength10,\r
FALSE\r
);\r
- //\r
+\r
+ ScsiDiskDevice->Cdb16Byte = FALSE;\r
+ if ((!EFI_ERROR (CommandStatus)) && (CapacityData10.LastLba3 == 0xff) && (CapacityData10.LastLba2 == 0xff) &&\r
+ (CapacityData10.LastLba1 == 0xff) && (CapacityData10.LastLba0 == 0xff)) {\r
+ //\r
+ // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB\r
+ //\r
+ ScsiDiskDevice->Cdb16Byte = TRUE;\r
+ //\r
+ // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock\r
+ // and LowestAlignedLba\r
+ //\r
+ CommandStatus = ScsiReadCapacity16Command (\r
+ ScsiDiskDevice->ScsiIo,\r
+ EFI_TIMER_PERIOD_SECONDS (1),\r
+ NULL,\r
+ &SenseDataLength,\r
+ &HostAdapterStatus,\r
+ &TargetStatus,\r
+ (VOID *) &CapacityData16,\r
+ &DataLength16,\r
+ FALSE\r
+ );\r
+ }\r
+\r
+ //\r
// no need to check HostAdapterStatus and TargetStatus\r
//\r
if (CommandStatus == EFI_SUCCESS) {\r
- GetMediaInfo (ScsiDiskDevice, &CapacityData);\r
+ GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);\r
return EFI_SUCCESS;\r
\r
} else if (CommandStatus == EFI_NOT_READY) {\r
}\r
\r
//\r
- // if goes here, meant SubmitReadCapacityCommand() failed.\r
+ // if goes here, meant ScsiReadCapacityCommand() failed.\r
// if ScsiDiskRequestSenseKeys() succeeds at last,\r
- // better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
+ // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
//\r
MaxRetry = 3;\r
for (Index = 0; Index < MaxRetry; Index++) {\r
Retrieve all sense keys from the device.\r
\r
When encountering error during the process, if retrieve sense keys before\r
- error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,\r
+ error encountered, it returns the sense keys with return status set to EFI_SUCCESS,\r
and NeedRetry set to FALSE; otherwize, return the proper return status.\r
\r
@param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
UINT8 TargetStatus;\r
\r
FallStatus = EFI_SUCCESS;\r
- SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
+ SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);\r
\r
ZeroMem (\r
ScsiDiskDevice->SenseData,\r
Get information from media read capacity command.\r
\r
@param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
- @param Capacity The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
+ @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
+ @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16\r
\r
**/\r
VOID\r
GetMediaInfo (\r
- IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
- IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity\r
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
+ IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,\r
+ IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16\r
)\r
{\r
- ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity->LastLba3 << 24) |\r
- (Capacity->LastLba2 << 16) |\r
- (Capacity->LastLba1 << 8) |\r
- Capacity->LastLba0;\r
+ UINT8 *Ptr;\r
+\r
+ ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;\r
+ ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;\r
+ \r
+\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |\r
+ (Capacity10->LastLba2 << 16) |\r
+ (Capacity10->LastLba1 << 8) |\r
+ Capacity10->LastLba0;\r
+ \r
+ ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |\r
+ (Capacity10->BlockSize2 << 16) | \r
+ (Capacity10->BlockSize1 << 8) |\r
+ Capacity10->BlockSize0;\r
+ ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; \r
+ } else {\r
+\r
+ Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;\r
+ *Ptr++ = Capacity16->LastLba0;\r
+ *Ptr++ = Capacity16->LastLba1;\r
+ *Ptr++ = Capacity16->LastLba2;\r
+ *Ptr++ = Capacity16->LastLba3;\r
+ *Ptr++ = Capacity16->LastLba4;\r
+ *Ptr++ = Capacity16->LastLba5;\r
+ *Ptr++ = Capacity16->LastLba6;\r
+ *Ptr = Capacity16->LastLba7;\r
+ \r
+ ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |\r
+ (Capacity16->BlockSize2 << 16) | \r
+ (Capacity16->BlockSize1 << 8) |\r
+ Capacity16->BlockSize0;\r
+\r
+ ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8)|(Capacity16->LowestAlignLogic1);\r
+ ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = Capacity16->LogicPerPhysical;\r
+ ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2; \r
+ }\r
+\r
\r
ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;\r
- ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity->BlockSize3 << 24) |\r
- (Capacity->BlockSize2 << 16) | \r
- (Capacity->BlockSize1 << 8) |\r
- Capacity->BlockSize0;\r
+ \r
if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
}\r
IN OUT SCSI_DISK_DEV *ScsiDiskDevice\r
)\r
{\r
- ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.RMB == 1) ? 0 : 1);\r
+ ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);\r
ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);\r
}\r
\r
/**\r
Read sector from SCSI Disk.\r
\r
- @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV\r
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
@param Buffer The buffer to fill in the read out data\r
@param Lba Logic block address\r
@param NumberOfBlocks The number of blocks to read\r
)\r
{\r
UINTN BlocksRemaining;\r
- UINT32 Lba32;\r
UINT8 *PtrBuffer;\r
UINT32 BlockSize;\r
UINT32 ByteCount;\r
\r
BlocksRemaining = NumberOfBlocks;\r
BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+ \r
//\r
- // limit the data bytes that can be transferred by one Read(10) Command\r
+ // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
//\r
- MaxBlock = 65536;\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ MaxBlock = 0xFFFF;\r
+ } else {\r
+ MaxBlock = 0xFFFFFFFF;\r
+ }\r
\r
PtrBuffer = Buffer;\r
- Lba32 = (UINT32) Lba;\r
\r
while (BlocksRemaining > 0) {\r
\r
if (BlocksRemaining <= MaxBlock) {\r
-\r
- SectorCount = (UINT16) BlocksRemaining;\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ } else {\r
+ SectorCount = (UINT32) BlocksRemaining;\r
+ }\r
} else {\r
-\r
SectorCount = MaxBlock;\r
}\r
\r
\r
MaxRetry = 2;\r
for (Index = 0; Index < MaxRetry; Index++) {\r
-\r
- Status = ScsiDiskRead10 (\r
- ScsiDiskDevice,\r
- &NeedRetry,\r
- &SenseData,\r
- &NumberOfSenseKeys,\r
- Timeout,\r
- PtrBuffer,\r
- &ByteCount,\r
- Lba32,\r
- SectorCount\r
- );\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskRead10 (\r
+ ScsiDiskDevice,\r
+ &NeedRetry,\r
+ &SenseData,\r
+ &NumberOfSenseKeys,\r
+ Timeout,\r
+ PtrBuffer,\r
+ &ByteCount,\r
+ (UINT32) Lba,\r
+ SectorCount\r
+ );\r
+ } else {\r
+ Status = ScsiDiskRead16 (\r
+ ScsiDiskDevice,\r
+ &NeedRetry,\r
+ &SenseData,\r
+ &NumberOfSenseKeys,\r
+ Timeout,\r
+ PtrBuffer,\r
+ &ByteCount,\r
+ Lba,\r
+ SectorCount\r
+ );\r
+ }\r
if (!EFI_ERROR (Status)) {\r
break;\r
}\r
//\r
SectorCount = ByteCount / BlockSize;\r
\r
- Lba32 += SectorCount;\r
+ Lba += SectorCount;\r
PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
BlocksRemaining -= SectorCount;\r
}\r
/**\r
Write sector to SCSI Disk.\r
\r
- @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV\r
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
@param Buffer The buffer of data to be written into SCSI Disk\r
@param Lba Logic block address\r
@param NumberOfBlocks The number of blocks to read\r
)\r
{\r
UINTN BlocksRemaining;\r
- UINT32 Lba32;\r
UINT8 *PtrBuffer;\r
UINT32 BlockSize;\r
UINT32 ByteCount;\r
\r
BlocksRemaining = NumberOfBlocks;\r
BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+\r
//\r
- // limit the data bytes that can be transferred by one Write(10) Command\r
+ // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
//\r
- MaxBlock = 65536;\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ MaxBlock = 0xFFFF;\r
+ } else {\r
+ MaxBlock = 0xFFFFFFFF;\r
+ }\r
\r
PtrBuffer = Buffer;\r
- Lba32 = (UINT32) Lba;\r
\r
while (BlocksRemaining > 0) {\r
\r
if (BlocksRemaining <= MaxBlock) {\r
-\r
- SectorCount = (UINT16) BlocksRemaining;\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ } else {\r
+ SectorCount = (UINT32) BlocksRemaining;\r
+ }\r
} else {\r
-\r
SectorCount = MaxBlock;\r
}\r
\r
Timeout = EFI_TIMER_PERIOD_SECONDS (2);\r
MaxRetry = 2;\r
for (Index = 0; Index < MaxRetry; Index++) {\r
- Status = ScsiDiskWrite10 (\r
- ScsiDiskDevice,\r
- &NeedRetry,\r
- &SenseData,\r
- &NumberOfSenseKeys,\r
- Timeout,\r
- PtrBuffer,\r
- &ByteCount,\r
- Lba32,\r
- SectorCount\r
- );\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskWrite10 (\r
+ ScsiDiskDevice,\r
+ &NeedRetry,\r
+ &SenseData,\r
+ &NumberOfSenseKeys,\r
+ Timeout,\r
+ PtrBuffer,\r
+ &ByteCount,\r
+ (UINT32) Lba,\r
+ SectorCount\r
+ );\r
+ } else {\r
+ Status = ScsiDiskWrite16 (\r
+ ScsiDiskDevice,\r
+ &NeedRetry,\r
+ &SenseData,\r
+ &NumberOfSenseKeys,\r
+ Timeout,\r
+ PtrBuffer,\r
+ &ByteCount,\r
+ Lba,\r
+ SectorCount\r
+ ); \r
+ }\r
if (!EFI_ERROR (Status)) {\r
break;\r
}\r
//\r
SectorCount = ByteCount / BlockSize;\r
\r
- Lba32 += SectorCount;\r
+ Lba += SectorCount;\r
PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
BlocksRemaining -= SectorCount;\r
}\r
\r
\r
/**\r
- Sumbmit Read command.\r
+ Submit Read(10) command.\r
\r
@param ScsiDiskDevice The pointer of ScsiDiskDevice\r
@param NeedRetry The pointer of flag indicates if needs retry if error happens\r
\r
\r
/**\r
- Submit Write Command.\r
+ Submit Write(10) Command.\r
\r
@param ScsiDiskDevice The pointer of ScsiDiskDevice\r
@param NeedRetry The pointer of flag indicates if needs retry if error happens\r
}\r
\r
\r
+/**\r
+ Submit Read(16) command.\r
+\r
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
+ @param SenseDataArray NOT used yet in this function\r
+ @param NumberOfSenseKeys The number of sense key\r
+ @param Timeout The time to complete the command\r
+ @param DataBuffer The buffer to fill with the read out data\r
+ @param DataLength The length of buffer\r
+ @param StartLba The start logic block address\r
+ @param SectorSize The size of sector\r
+\r
+ @return EFI_STATUS is returned by calling ScsiRead10Command().\r
+**/\r
+EFI_STATUS\r
+ScsiDiskRead16 (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ OUT BOOLEAN *NeedRetry,\r
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
+ OUT UINTN *NumberOfSenseKeys,\r
+ IN UINT64 Timeout,\r
+ OUT UINT8 *DataBuffer,\r
+ IN OUT UINT32 *DataLength,\r
+ IN UINT64 StartLba,\r
+ IN UINT32 SectorSize\r
+ )\r
+{\r
+ UINT8 SenseDataLength;\r
+ EFI_STATUS Status;\r
+ UINT8 HostAdapterStatus;\r
+ UINT8 TargetStatus;\r
+\r
+ *NeedRetry = FALSE;\r
+ *NumberOfSenseKeys = 0;\r
+ SenseDataLength = 0;\r
+ Status = ScsiRead16Command (\r
+ ScsiDiskDevice->ScsiIo,\r
+ Timeout,\r
+ NULL,\r
+ &SenseDataLength,\r
+ &HostAdapterStatus,\r
+ &TargetStatus,\r
+ DataBuffer,\r
+ DataLength,\r
+ StartLba,\r
+ SectorSize\r
+ );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submit Write(16) Command.\r
+\r
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
+ @param SenseDataArray NOT used yet in this function\r
+ @param NumberOfSenseKeys The number of sense key\r
+ @param Timeout The time to complete the command\r
+ @param DataBuffer The buffer to fill with the read out data\r
+ @param DataLength The length of buffer\r
+ @param StartLba The start logic block address\r
+ @param SectorSize The size of sector\r
+\r
+ @return EFI_STATUS is returned by calling ScsiWrite10Command().\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskWrite16 (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ OUT BOOLEAN *NeedRetry,\r
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
+ OUT UINTN *NumberOfSenseKeys,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 *DataBuffer,\r
+ IN OUT UINT32 *DataLength,\r
+ IN UINT64 StartLba,\r
+ IN UINT32 SectorSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SenseDataLength;\r
+ UINT8 HostAdapterStatus;\r
+ UINT8 TargetStatus;\r
+\r
+ *NeedRetry = FALSE;\r
+ *NumberOfSenseKeys = 0;\r
+ SenseDataLength = 0;\r
+ Status = ScsiWrite16Command (\r
+ ScsiDiskDevice->ScsiIo,\r
+ Timeout,\r
+ NULL,\r
+ &SenseDataLength,\r
+ &HostAdapterStatus,\r
+ &TargetStatus,\r
+ DataBuffer,\r
+ DataLength,\r
+ StartLba,\r
+ SectorSize\r
+ );\r
+ return Status;\r
+}\r
+\r
+\r
/**\r
Check sense key to find if media presents.\r
\r
@param SenseCounts The number of sense key\r
\r
@retval TRUE Media is changed.\r
- @retval FALSE Medit is NOT changed.\r
+ @retval FALSE Media is NOT changed.\r
**/\r
BOOLEAN\r
ScsiDiskIsMediaChange (\r
\r
ScsiDiskDevice = NULL;\r
}\r
+\r
+/**\r
+ Determine if Block Io should be produced.\r
+ \r
+\r
+ @param ChildHandle Child Handle to retrieve Parent information.\r
+ \r
+ @retval TRUE Should produce Block Io.\r
+ @retval FALSE Should not produce Block Io.\r
+\r
+**/ \r
+BOOLEAN\r
+DetermineInstallBlockIo (\r
+ IN EFI_HANDLE ChildHandle\r
+ ) \r
+{\r
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;\r
+\r
+ //\r
+ // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,\r
+ // check its attribute, logic or physical.\r
+ //\r
+ ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);\r
+ if (ExtScsiPassThru != NULL) {\r
+ if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,\r
+ // check its attribute, logic or physical.\r
+ //\r
+ ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);\r
+ if (ScsiPassThru != NULL) {\r
+ if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Search protocol database and check to see if the protocol\r
+ specified by ProtocolGuid is present on a ControllerHandle and opened by\r
+ ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+ If the ControllerHandle is found, then the protocol specified by ProtocolGuid\r
+ will be opened on it. \r
+ \r
+\r
+ @param ProtocolGuid ProtocolGuid pointer.\r
+ @param ChildHandle Child Handle to retrieve Parent information.\r
+ \r
+**/ \r
+VOID *\r
+EFIAPI\r
+GetParentProtocol (\r
+ IN EFI_GUID *ProtocolGuid,\r
+ IN EFI_HANDLE ChildHandle\r
+ ) \r
+{\r
+ UINTN Index;\r
+ UINTN HandleCount;\r
+ VOID *Interface; \r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+\r
+ //\r
+ // Retrieve the list of all handles from the handle database\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ ProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle \r
+ //\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->FreePool (HandleBuffer);\r
+ return Interface;\r
+ }\r
+ }\r
+ }\r
+\r
+ gBS->FreePool (HandleBuffer);\r
+ return NULL;\r
+} \r
+\r
+/**\r
+ Provides inquiry information for the controller type.\r
+ \r
+ This function is used by the IDE bus driver to get inquiry data. Data format\r
+ of Identify data is defined by the Interface GUID.\r
+\r
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.\r
+ @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.\r
+\r
+ @retval EFI_SUCCESS The command was accepted without any errors.\r
+ @retval EFI_NOT_FOUND Device does not support this data class \r
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device \r
+ @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoInquiry (\r
+ IN EFI_DISK_INFO_PROTOCOL *This,\r
+ IN OUT VOID *InquiryData,\r
+ IN OUT UINT32 *InquiryDataSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SCSI_DISK_DEV *ScsiDiskDevice;\r
+\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
+\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {\r
+ Status = EFI_SUCCESS;\r
+ CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));\r
+ }\r
+ *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Provides identify information for the controller type.\r
+\r
+ This function is used by the IDE bus driver to get identify data. Data format\r
+ of Identify data is defined by the Interface GUID.\r
+\r
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL \r
+ instance.\r
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.\r
+ @param[in, out] IdentifyDataSize Pointer to the value for the identify data\r
+ size.\r
+\r
+ @retval EFI_SUCCESS The command was accepted without any errors.\r
+ @retval EFI_NOT_FOUND Device does not support this data class \r
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device \r
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoIdentify (\r
+ IN EFI_DISK_INFO_PROTOCOL *This,\r
+ IN OUT VOID *IdentifyData,\r
+ IN OUT UINT32 *IdentifyDataSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SCSI_DISK_DEV *ScsiDiskDevice;\r
+\r
+ if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
+ //\r
+ // Physical SCSI bus does not support this data class. \r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
+\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {\r
+ Status = EFI_SUCCESS;\r
+ CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));\r
+ }\r
+ *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Provides sense data information for the controller type.\r
+ \r
+ This function is used by the IDE bus driver to get sense data. \r
+ Data format of Sense data is defined by the Interface GUID.\r
+\r
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
+ @param[in, out] SenseData Pointer to the SenseData.\r
+ @param[in, out] SenseDataSize Size of SenseData in bytes.\r
+ @param[out] SenseDataNumber Pointer to the value for the sense data size.\r
+\r
+ @retval EFI_SUCCESS The command was accepted without any errors.\r
+ @retval EFI_NOT_FOUND Device does not support this data class.\r
+ @retval EFI_DEVICE_ERROR Error reading SenseData from device.\r
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoSenseData (\r
+ IN EFI_DISK_INFO_PROTOCOL *This,\r
+ IN OUT VOID *SenseData,\r
+ IN OUT UINT32 *SenseDataSize,\r
+ OUT UINT8 *SenseDataNumber\r
+ )\r
+{\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ This function is used by the IDE bus driver to get controller information.\r
+\r
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. \r
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.\r
+ @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.\r
+\r
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.\r
+ @retval EFI_UNSUPPORTED This is not an IDE device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoWhichIde (\r
+ IN EFI_DISK_INFO_PROTOCOL *This,\r
+ OUT UINT32 *IdeChannel,\r
+ OUT UINT32 *IdeDevice\r
+ )\r
+{\r
+ SCSI_DISK_DEV *ScsiDiskDevice;\r
+\r
+ if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
+ //\r
+ // This is not an IDE physical device.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
+ *IdeChannel = ScsiDiskDevice->Channel;\r
+ *IdeDevice = ScsiDiskDevice->Device;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Issues ATA IDENTIFY DEVICE command to identify ATAPI device.\r
+\r
+ This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to\r
+ implement Identify() interface for DiskInfo protocol. The ATA command is sent\r
+ via SCSI Request Packet.\r
+\r
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
+ \r
+ @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.\r
+ @retval others Some error occurred during the identification that ATAPI device.\r
+\r
+**/ \r
+EFI_STATUS\r
+AtapiIdentifyDevice (\r
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice\r
+ )\r
+{\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
+ UINT8 Cdb[6];\r
+\r
+ //\r
+ // Initialize SCSI REQUEST_PACKET and 6-byte Cdb\r
+ //\r
+ ZeroMem (&CommandPacket, sizeof (CommandPacket));\r
+ ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+ Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;\r
+ CommandPacket.Timeout = EFI_TIMER_PERIOD_SECONDS (1);\r
+ CommandPacket.Cdb = Cdb;\r
+ CommandPacket.CdbLength = (UINT8) sizeof (Cdb);\r
+ CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;\r
+ CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);\r
+\r
+ return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);\r
+}\r
+\r
+\r
+/**\r
+ Initialize the installation of DiskInfo protocol.\r
+\r
+ This function prepares for the installation of DiskInfo protocol on the child handle.\r
+ By default, it installs DiskInfo protocol with SCSI interface GUID. If it further\r
+ detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID\r
+ to be IDE/AHCI interface GUID.\r
+\r
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
+ @param ChildHandle Child handle to install DiskInfo protocol.\r
+ \r
+**/ \r
+VOID\r
+InitializeInstallDiskInfo (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;\r
+ ATAPI_DEVICE_PATH *AtapiDevicePath;\r
+ SATA_DEVICE_PATH *SataDevicePath;\r
+ UINTN IdentifyRetry;\r
+\r
+ Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);\r
+ //\r
+ // Device Path protocol must be installed on the device handle. \r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+ //\r
+ // Copy the DiskInfo protocol template.\r
+ //\r
+ CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));\r
+\r
+ while (!IsDevicePathEnd (DevicePathNode)) {\r
+ ChildDevicePathNode = NextDevicePathNode (DevicePathNode);\r
+ if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&\r
+ (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&\r
+ (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&\r
+ ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||\r
+ (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {\r
+\r
+ IdentifyRetry = 3;\r
+ do {\r
+ //\r
+ // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol\r
+ // with IDE/AHCI interface GUID.\r
+ //\r
+ Status = AtapiIdentifyDevice (ScsiDiskDevice);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {\r
+ //\r
+ // We find the valid ATAPI device path\r
+ //\r
+ AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;\r
+ ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;\r
+ ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;\r
+ //\r
+ // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device. \r
+ //\r
+ CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);\r
+ } else {\r
+ //\r
+ // We find the valid SATA device path\r
+ //\r
+ SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;\r
+ ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;\r
+ ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;\r
+ //\r
+ // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device. \r
+ //\r
+ CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);\r
+ }\r
+ return;\r
+ }\r
+ } while (--IdentifyRetry > 0);\r
+ }\r
+ DevicePathNode = ChildDevicePathNode;\r
+ }\r
+\r
+ return;\r
+}\r