Allocate aligned buffer to satisfy the IoAlign requirement of high level protocol.

Signed-off-by: lzeng14
Reviewed-by: erictian

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12788 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
lzeng14 2011-11-25 09:52:12 +00:00
parent 79d07c66d9
commit 957fe09353
3 changed files with 182 additions and 48 deletions

View File

@ -129,7 +129,7 @@ FreeAlignedBuffer (
) )
{ {
if (Buffer != NULL) { if (Buffer != NULL) {
FreePages (Buffer, EFI_SIZE_TO_PAGES (BufferSize)); FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
} }
} }

View File

@ -2,7 +2,7 @@
SCSI Bus driver that layers on every SCSI Pass Thru and SCSI Bus driver that layers on every SCSI Pass Thru and
Extended SCSI Pass Thru protocol in the system. Extended SCSI Pass Thru protocol in the system.
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -71,6 +71,49 @@ NotifyFunction (
IN VOID *Context IN VOID *Context
); );
/**
Allocates an aligned buffer for SCSI device.
This function allocates an aligned buffer for the SCSI device to perform
SCSI pass through operations. The alignment requirement is from SCSI pass
through interface.
@param ScsiIoDevice The SCSI child device involved for the operation.
@param BufferSize The request buffer size.
@return A pointer to the aligned buffer or NULL if the allocation fails.
**/
VOID *
AllocateAlignedBuffer (
IN SCSI_IO_DEV *ScsiIoDevice,
IN UINTN BufferSize
)
{
return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign);
}
/**
Frees an aligned buffer for SCSI device.
This function frees an aligned buffer for the SCSI device to perform
SCSI pass through operations.
@param Buffer The aligned buffer to be freed.
@param BufferSize The request buffer size.
**/
VOID
FreeAlignedBuffer (
IN VOID *Buffer,
IN UINTN BufferSize
)
{
if (Buffer != NULL) {
FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
}
}
/** /**
The user Entry Point for module ScsiBus. The user code starts with this function. The user Entry Point for module ScsiBus. The user code starts with this function.
@ -1178,30 +1221,37 @@ DiscoverScsiDevice (
UINT8 SenseDataLength; UINT8 SenseDataLength;
UINT8 HostAdapterStatus; UINT8 HostAdapterStatus;
UINT8 TargetStatus; UINT8 TargetStatus;
EFI_SCSI_SENSE_DATA SenseData; EFI_SCSI_INQUIRY_DATA *InquiryData;
EFI_SCSI_INQUIRY_DATA InquiryData;
UINT8 MaxRetry; UINT8 MaxRetry;
UINT8 Index; UINT8 Index;
BOOLEAN ScsiDeviceFound;
HostAdapterStatus = 0; HostAdapterStatus = 0;
TargetStatus = 0; TargetStatus = 0;
InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));
if (InquiryData == NULL) {
ScsiDeviceFound = FALSE;
goto Done;
}
// //
// Using Inquiry command to scan for the device // Using Inquiry command to scan for the device
// //
InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA); InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA); SenseDataLength = 0;
ZeroMem (&InquiryData, InquiryDataLength); ZeroMem (InquiryData, InquiryDataLength);
MaxRetry = 2; MaxRetry = 2;
for (Index = 0; Index < MaxRetry; Index++) { for (Index = 0; Index < MaxRetry; Index++) {
Status = ScsiInquiryCommand ( Status = ScsiInquiryCommand (
&ScsiIoDevice->ScsiIo, &ScsiIoDevice->ScsiIo,
EFI_TIMER_PERIOD_SECONDS (1), EFI_TIMER_PERIOD_SECONDS (1),
(VOID *) &SenseData, NULL,
&SenseDataLength, &SenseDataLength,
&HostAdapterStatus, &HostAdapterStatus,
&TargetStatus, &TargetStatus,
(VOID *) &InquiryData, (VOID *) InquiryData,
&InquiryDataLength, &InquiryDataLength,
FALSE FALSE
); );
@ -1210,47 +1260,57 @@ DiscoverScsiDevice (
} else if ((Status == EFI_BAD_BUFFER_SIZE) || } else if ((Status == EFI_BAD_BUFFER_SIZE) ||
(Status == EFI_INVALID_PARAMETER) || (Status == EFI_INVALID_PARAMETER) ||
(Status == EFI_UNSUPPORTED)) { (Status == EFI_UNSUPPORTED)) {
return FALSE; ScsiDeviceFound = FALSE;
goto Done;
} }
} }
if (Index == MaxRetry) { if (Index == MaxRetry) {
return FALSE; ScsiDeviceFound = FALSE;
goto Done;
} }
// //
// Retrieved inquiry data successfully // Retrieved inquiry data successfully
// //
if ((InquiryData.Peripheral_Qualifier != 0) && if ((InquiryData->Peripheral_Qualifier != 0) &&
(InquiryData.Peripheral_Qualifier != 3)) { (InquiryData->Peripheral_Qualifier != 3)) {
return FALSE; ScsiDeviceFound = FALSE;
goto Done;
} }
if (InquiryData.Peripheral_Qualifier == 3) { if (InquiryData->Peripheral_Qualifier == 3) {
if (InquiryData.Peripheral_Type != 0x1f) { if (InquiryData->Peripheral_Type != 0x1f) {
return FALSE; ScsiDeviceFound = FALSE;
goto Done;
} }
} }
if (0x1e >= InquiryData.Peripheral_Type && InquiryData.Peripheral_Type >= 0xa) { if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) {
return FALSE; ScsiDeviceFound = FALSE;
goto Done;
} }
// //
// valid device type and peripheral qualifier combination. // valid device type and peripheral qualifier combination.
// //
ScsiIoDevice->ScsiDeviceType = InquiryData.Peripheral_Type; ScsiIoDevice->ScsiDeviceType = InquiryData->Peripheral_Type;
ScsiIoDevice->RemovableDevice = InquiryData.Rmb; ScsiIoDevice->RemovableDevice = InquiryData->Rmb;
if (InquiryData.Version == 0) { if (InquiryData->Version == 0) {
ScsiIoDevice->ScsiVersion = 0; ScsiIoDevice->ScsiVersion = 0;
} else { } else {
// //
// ANSI-approved version // ANSI-approved version
// //
ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x07); ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07);
} }
return TRUE; ScsiDeviceFound = TRUE;
Done:
FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
return ScsiDeviceFound;
} }

View File

@ -32,6 +32,48 @@ EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
ScsiDiskInfoWhichIde ScsiDiskInfoWhichIde
}; };
/**
Allocates an aligned buffer for SCSI disk.
This function allocates an aligned buffer for the SCSI disk to perform
SCSI IO operations. The alignment requirement is from SCSI IO interface.
@param ScsiDiskDevice The SCSI disk involved for the operation.
@param BufferSize The request buffer size.
@return A pointer to the aligned buffer or NULL if the allocation fails.
**/
VOID *
AllocateAlignedBuffer (
IN SCSI_DISK_DEV *ScsiDiskDevice,
IN UINTN BufferSize
)
{
return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);
}
/**
Frees an aligned buffer for SCSI disk.
This function frees an aligned buffer for the SCSI disk to perform
SCSI IO operations.
@param Buffer The aligned buffer to be freed.
@param BufferSize The request buffer size.
**/
VOID
FreeAlignedBuffer (
IN VOID *Buffer,
IN UINTN BufferSize
)
{
if (Buffer != NULL) {
FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
}
}
/** /**
The user Entry Point for module ScsiDisk. The user Entry Point for module ScsiDisk.
@ -902,8 +944,8 @@ ScsiDiskInquiryDevice (
EFI_STATUS Status; EFI_STATUS Status;
UINT8 MaxRetry; UINT8 MaxRetry;
UINT8 Index; UINT8 Index;
EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE SupportedVpdPages; EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
EFI_SCSI_BLOCK_LIMITS_VPD_PAGE BlockLimits; EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;
UINTN PageLength; UINTN PageLength;
InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA); InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
@ -930,8 +972,13 @@ ScsiDiskInquiryDevice (
// //
// Check whether the device supports Block Limits VPD page (0xB0) // Check whether the device supports Block Limits VPD page (0xB0)
// //
ZeroMem (&SupportedVpdPages, sizeof (SupportedVpdPages)); SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
InquiryDataLength = sizeof (SupportedVpdPages); if (SupportedVpdPages == NULL) {
*NeedRetry = FALSE;
return EFI_DEVICE_ERROR;
}
ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
SenseDataLength = 0; SenseDataLength = 0;
Status = ScsiInquiryCommandEx ( Status = ScsiInquiryCommandEx (
ScsiDiskDevice->ScsiIo, ScsiDiskDevice->ScsiIo,
@ -940,16 +987,16 @@ ScsiDiskInquiryDevice (
&SenseDataLength, &SenseDataLength,
&HostAdapterStatus, &HostAdapterStatus,
&TargetStatus, &TargetStatus,
(VOID *) &SupportedVpdPages, (VOID *) SupportedVpdPages,
&InquiryDataLength, &InquiryDataLength,
TRUE, TRUE,
EFI_SCSI_PAGE_CODE_SUPPORTED_VPD EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
); );
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
PageLength = (SupportedVpdPages.PageLength2 << 8) PageLength = (SupportedVpdPages->PageLength2 << 8)
| SupportedVpdPages.PageLength1; | SupportedVpdPages->PageLength1;
for (Index = 0; Index < PageLength; Index++) { for (Index = 0; Index < PageLength; Index++) {
if (SupportedVpdPages.SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) { if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
break; break;
} }
} }
@ -958,8 +1005,14 @@ ScsiDiskInquiryDevice (
// Query the Block Limits VPD page // Query the Block Limits VPD page
// //
if (Index < PageLength) { if (Index < PageLength) {
ZeroMem (&BlockLimits, sizeof (BlockLimits)); BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
InquiryDataLength = sizeof (BlockLimits); if (BlockLimits == NULL) {
FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
*NeedRetry = FALSE;
return EFI_DEVICE_ERROR;
}
ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
SenseDataLength = 0; SenseDataLength = 0;
Status = ScsiInquiryCommandEx ( Status = ScsiInquiryCommandEx (
ScsiDiskDevice->ScsiIo, ScsiDiskDevice->ScsiIo,
@ -968,18 +1021,22 @@ ScsiDiskInquiryDevice (
&SenseDataLength, &SenseDataLength,
&HostAdapterStatus, &HostAdapterStatus,
&TargetStatus, &TargetStatus,
(VOID *) &BlockLimits, (VOID *) BlockLimits,
&InquiryDataLength, &InquiryDataLength,
TRUE, TRUE,
EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
); );
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity = ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
(BlockLimits.OptimalTransferLengthGranularity2 << 8) | (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
BlockLimits.OptimalTransferLengthGranularity1; BlockLimits->OptimalTransferLengthGranularity1;
} }
FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
} }
} }
FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
} }
} }
@ -1285,15 +1342,26 @@ ScsiDiskReadCapacity (
UINT8 SenseDataLength; UINT8 SenseDataLength;
UINT32 DataLength10; UINT32 DataLength10;
UINT32 DataLength16; UINT32 DataLength16;
EFI_SCSI_DISK_CAPACITY_DATA CapacityData10; EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16; EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
if (CapacityData10 == NULL) {
*NeedRetry = FALSE;
return EFI_DEVICE_ERROR;
}
CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
if (CapacityData16 == NULL) {
FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
*NeedRetry = FALSE;
return EFI_DEVICE_ERROR;
}
SenseDataLength = 0; SenseDataLength = 0;
DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA); DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16); DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA)); ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16)); ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
*NumberOfSenseKeys = 0; *NumberOfSenseKeys = 0;
*NeedRetry = FALSE; *NeedRetry = FALSE;
@ -1309,14 +1377,14 @@ ScsiDiskReadCapacity (
&SenseDataLength, &SenseDataLength,
&HostAdapterStatus, &HostAdapterStatus,
&TargetStatus, &TargetStatus,
(VOID *) &CapacityData10, (VOID *) CapacityData10,
&DataLength10, &DataLength10,
FALSE FALSE
); );
ScsiDiskDevice->Cdb16Byte = FALSE; ScsiDiskDevice->Cdb16Byte = FALSE;
if ((!EFI_ERROR (CommandStatus)) && (CapacityData10.LastLba3 == 0xff) && (CapacityData10.LastLba2 == 0xff) && if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
(CapacityData10.LastLba1 == 0xff) && (CapacityData10.LastLba0 == 0xff)) { (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
// //
// use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
// //
@ -1332,7 +1400,7 @@ ScsiDiskReadCapacity (
&SenseDataLength, &SenseDataLength,
&HostAdapterStatus, &HostAdapterStatus,
&TargetStatus, &TargetStatus,
(VOID *) &CapacityData16, (VOID *) CapacityData16,
&DataLength16, &DataLength16,
FALSE FALSE
); );
@ -1342,17 +1410,23 @@ ScsiDiskReadCapacity (
// no need to check HostAdapterStatus and TargetStatus // no need to check HostAdapterStatus and TargetStatus
// //
if (CommandStatus == EFI_SUCCESS) { if (CommandStatus == EFI_SUCCESS) {
GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16); GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
return EFI_SUCCESS; return EFI_SUCCESS;
}
} else if (CommandStatus == EFI_NOT_READY) {
FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
if (CommandStatus == EFI_NOT_READY) {
*NeedRetry = TRUE; *NeedRetry = TRUE;
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
} else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) { } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
*NeedRetry = FALSE; *NeedRetry = FALSE;
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
} }
// //
// go ahead to check HostAdapterStatus and TargetStatus // go ahead to check HostAdapterStatus and TargetStatus
// (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)