mirror of https://github.com/acidanthera/audk.git
2354 lines
59 KiB
C
2354 lines
59 KiB
C
/*++
|
|
|
|
Copyright (c) 2006, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
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
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
ScsiDisk.c
|
|
|
|
Abstract:
|
|
|
|
--*/
|
|
|
|
#include "ScsiDisk.h"
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
);
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
|
|
ScsiDiskDriverBindingSupported,
|
|
ScsiDiskDriverBindingStart,
|
|
ScsiDiskDriverBindingStop,
|
|
0x10,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Controller - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SCSI_IO_PROTOCOL *ScsiIo;
|
|
UINT8 DeviceType;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiScsiIoProtocolGuid,
|
|
(VOID **) &ScsiIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
|
|
if (!EFI_ERROR (Status)) {
|
|
if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiScsiIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Controller - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SCSI_IO_PROTOCOL *ScsiIo;
|
|
SCSI_DISK_DEV *ScsiDiskDevice;
|
|
BOOLEAN Temp;
|
|
UINT8 Index;
|
|
UINT8 MaxRetry;
|
|
BOOLEAN NeedRetry;
|
|
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
sizeof (SCSI_DISK_DEV),
|
|
(VOID **) &ScsiDiskDevice
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ZeroMem (ScsiDiskDevice, sizeof (SCSI_DISK_DEV));
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiScsiIoProtocolGuid,
|
|
(VOID **) &ScsiIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (ScsiDiskDevice);
|
|
return Status;
|
|
}
|
|
|
|
ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;
|
|
ScsiDiskDevice->ScsiIo = ScsiIo;
|
|
ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;
|
|
ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;
|
|
ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;
|
|
ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;
|
|
ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;
|
|
ScsiDiskDevice->Handle = Controller;
|
|
|
|
ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
|
|
switch (ScsiDiskDevice->DeviceType) {
|
|
case EFI_SCSI_TYPE_DISK:
|
|
ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
|
|
break;
|
|
|
|
case EFI_SCSI_TYPE_CDROM:
|
|
ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
|
|
break;
|
|
}
|
|
//
|
|
// The Sense Data Array's initial size is 6
|
|
//
|
|
ScsiDiskDevice->SenseDataNumber = 6;
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber,
|
|
(VOID **) &(ScsiDiskDevice->SenseData)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiScsiIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
gBS->FreePool (ScsiDiskDevice);
|
|
return Status;
|
|
}
|
|
|
|
ZeroMem (
|
|
ScsiDiskDevice->SenseData,
|
|
sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
|
|
);
|
|
|
|
//
|
|
// Retrive device information
|
|
//
|
|
MaxRetry = 2;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
|
|
if (!EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
if (!NeedRetry) {
|
|
gBS->FreePool (ScsiDiskDevice->SenseData);
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiScsiIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
gBS->FreePool (ScsiDiskDevice);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
//
|
|
// The second parameter "TRUE" means must
|
|
// retrieve media capacity
|
|
//
|
|
Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Controller,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&ScsiDiskDevice->BlkIo,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (ScsiDiskDevice->SenseData);
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiScsiIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
gBS->FreePool (ScsiDiskDevice);
|
|
return Status;
|
|
}
|
|
|
|
ScsiDiskDevice->ControllerNameTable = NULL;
|
|
AddUnicodeString (
|
|
"eng",
|
|
gScsiDiskComponentName.SupportedLanguages,
|
|
&ScsiDiskDevice->ControllerNameTable,
|
|
(CHAR16 *) L"SCSI Disk Device"
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Controller - add argument and description to function comment
|
|
// TODO: NumberOfChildren - add argument and description to function comment
|
|
// TODO: ChildHandleBuffer - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_BLOCK_IO_PROTOCOL *BlkIo;
|
|
SCSI_DISK_DEV *ScsiDiskDevice;
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlkIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);
|
|
Status = gBS->UninstallProtocolInterface (
|
|
Controller,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&ScsiDiskDevice->BlkIo
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiScsiIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// errors met
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Block I/O Protocol Interface
|
|
//
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskReset (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
ExtendedVerification - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
SCSI_DISK_DEV *ScsiDiskDevice;
|
|
EFI_STATUS Status;
|
|
|
|
ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
|
|
|
|
Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
|
|
|
|
if (!ExtendedVerification) {
|
|
return Status;
|
|
}
|
|
|
|
Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskReadBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA LBA,
|
|
IN UINTN BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
MediaId - TODO: add argument description
|
|
LBA - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_NO_MEDIA - TODO: Add description for return value
|
|
EFI_MEDIA_CHANGED - TODO: Add description for return value
|
|
EFI_BAD_BUFFER_SIZE - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
SCSI_DISK_DEV *ScsiDiskDevice;
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
|
EFI_STATUS Status;
|
|
UINTN BlockSize;
|
|
UINTN NumberOfBlocks;
|
|
BOOLEAN MediaChange;
|
|
|
|
MediaChange = FALSE;
|
|
if (!Buffer) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (BufferSize == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
|
|
|
|
if (!IsDeviceFixed (ScsiDiskDevice)) {
|
|
|
|
Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (MediaChange) {
|
|
gBS->ReinstallProtocolInterface (
|
|
ScsiDiskDevice->Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&ScsiDiskDevice->BlkIo,
|
|
&ScsiDiskDevice->BlkIo
|
|
);
|
|
}
|
|
}
|
|
//
|
|
// Get the intrinsic block size
|
|
//
|
|
Media = ScsiDiskDevice->BlkIo.Media;
|
|
BlockSize = Media->BlockSize;
|
|
|
|
NumberOfBlocks = BufferSize / BlockSize;
|
|
|
|
if (!(Media->MediaPresent)) {
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
if (MediaId != Media->MediaId) {
|
|
return EFI_MEDIA_CHANGED;
|
|
}
|
|
|
|
if (BufferSize % BlockSize != 0) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
if (LBA > Media->LastBlock) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// if all the parameters are valid, then perform read sectors command
|
|
// to transfer data from device to host.
|
|
//
|
|
Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskWriteBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA LBA,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
MediaId - TODO: add argument description
|
|
LBA - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_NO_MEDIA - TODO: Add description for return value
|
|
EFI_MEDIA_CHANGED - TODO: Add description for return value
|
|
EFI_BAD_BUFFER_SIZE - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
SCSI_DISK_DEV *ScsiDiskDevice;
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
|
EFI_STATUS Status;
|
|
UINTN BlockSize;
|
|
UINTN NumberOfBlocks;
|
|
BOOLEAN MediaChange;
|
|
|
|
MediaChange = FALSE;
|
|
if (!Buffer) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (BufferSize == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
|
|
|
|
if (!IsDeviceFixed (ScsiDiskDevice)) {
|
|
|
|
Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (MediaChange) {
|
|
gBS->ReinstallProtocolInterface (
|
|
ScsiDiskDevice->Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&ScsiDiskDevice->BlkIo,
|
|
&ScsiDiskDevice->BlkIo
|
|
);
|
|
}
|
|
}
|
|
//
|
|
// Get the intrinsic block size
|
|
//
|
|
Media = ScsiDiskDevice->BlkIo.Media;
|
|
BlockSize = Media->BlockSize;
|
|
|
|
NumberOfBlocks = BufferSize / BlockSize;
|
|
|
|
if (!(Media->MediaPresent)) {
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
if (MediaId != Media->MediaId) {
|
|
return EFI_MEDIA_CHANGED;
|
|
}
|
|
|
|
if (BufferSize % BlockSize != 0) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
if (LBA > Media->LastBlock) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// if all the parameters are valid, then perform read sectors command
|
|
// to transfer data from device to host.
|
|
//
|
|
Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskFlushBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// return directly
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskDetectMedia (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
BOOLEAN MustReadCapacity,
|
|
BOOLEAN *MediaChange
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
MustReadCapacity - TODO: add argument description
|
|
MediaChange - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS ReadCapacityStatus;
|
|
EFI_SCSI_SENSE_DATA *SenseData;
|
|
UINTN NumberOfSenseKeys;
|
|
BOOLEAN NeedRetry;
|
|
BOOLEAN NeedReadCapacity;
|
|
UINT8 Index;
|
|
UINT8 MaxRetry;
|
|
EFI_BLOCK_IO_MEDIA OldMedia;
|
|
UINTN Action;
|
|
|
|
Status = EFI_SUCCESS;
|
|
ReadCapacityStatus = EFI_SUCCESS;
|
|
SenseData = NULL;
|
|
NumberOfSenseKeys = 0;
|
|
NeedReadCapacity = FALSE;
|
|
CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
|
|
// OldMedia = *(ScsiDiskDevice->BlkIo.Media);
|
|
|
|
*MediaChange = FALSE;
|
|
|
|
MaxRetry = 3;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
Status = ScsiDiskTestUnitReady (
|
|
ScsiDiskDevice,
|
|
&NeedRetry,
|
|
&SenseData,
|
|
&NumberOfSenseKeys
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
if (!NeedRetry) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if ((Index == MaxRetry) && EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = DetectMediaParsingSenseKeys (
|
|
ScsiDiskDevice,
|
|
SenseData,
|
|
NumberOfSenseKeys,
|
|
&Action
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// ACTION_NO_ACTION: need not read capacity
|
|
// other action code: need read capacity
|
|
//
|
|
if (Action == ACTION_NO_ACTION) {
|
|
NeedReadCapacity = FALSE;
|
|
} else {
|
|
NeedReadCapacity = TRUE;
|
|
}
|
|
|
|
//
|
|
// either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
|
|
// retrieve capacity via Read Capacity command
|
|
//
|
|
if (NeedReadCapacity || MustReadCapacity) {
|
|
|
|
//
|
|
// retrieve media information
|
|
//
|
|
MaxRetry = 3;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
|
|
ReadCapacityStatus = ScsiDiskReadCapacity (
|
|
ScsiDiskDevice,
|
|
&NeedRetry,
|
|
&SenseData,
|
|
&NumberOfSenseKeys
|
|
);
|
|
if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// analyze sense key to action
|
|
//
|
|
Status = DetectMediaParsingSenseKeys (
|
|
ScsiDiskDevice,
|
|
SenseData,
|
|
NumberOfSenseKeys,
|
|
&Action
|
|
);
|
|
//
|
|
// if Status is error, it may indicate crisis error,
|
|
// so return without retry.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
switch (Action) {
|
|
case ACTION_NO_ACTION:
|
|
//
|
|
// no retry
|
|
//
|
|
Index = MaxRetry;
|
|
break;
|
|
|
|
case ACTION_RETRY_COMMAND_LATER:
|
|
//
|
|
// retry the ReadCapacity later and continuously, until the condition
|
|
// no longer emerges.
|
|
// stall time is 100000us, or say 0.1 second.
|
|
//
|
|
gBS->Stall (100000);
|
|
Index = 0;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// other cases, just retry the command
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
|
|
//
|
|
// Media change information got from the device
|
|
//
|
|
*MediaChange = TRUE;
|
|
}
|
|
|
|
if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
|
|
*MediaChange = TRUE;
|
|
ScsiDiskDevice->BlkIo.Media->MediaId += 1;
|
|
}
|
|
|
|
if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
|
|
*MediaChange = TRUE;
|
|
ScsiDiskDevice->BlkIo.Media->MediaId += 1;
|
|
}
|
|
|
|
if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
|
|
*MediaChange = TRUE;
|
|
ScsiDiskDevice->BlkIo.Media->MediaId += 1;
|
|
}
|
|
|
|
if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
|
|
if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
|
|
//
|
|
// when change from no media to media present, reset the MediaId to 1.
|
|
//
|
|
ScsiDiskDevice->BlkIo.Media->MediaId = 1;
|
|
} else {
|
|
//
|
|
// when no media, reset the MediaId to zero.
|
|
//
|
|
ScsiDiskDevice->BlkIo.Media->MediaId = 0;
|
|
}
|
|
|
|
*MediaChange = TRUE;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskInquiryDevice (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
BOOLEAN *NeedRetry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
NeedRetry - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
UINT32 InquiryDataLength;
|
|
UINT8 SenseDataLength;
|
|
UINT8 HostAdapterStatus;
|
|
UINT8 TargetStatus;
|
|
EFI_SCSI_SENSE_DATA *SenseDataArray;
|
|
UINTN NumberOfSenseKeys;
|
|
EFI_STATUS Status;
|
|
UINT8 MaxRetry;
|
|
UINT8 Index;
|
|
|
|
InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
|
|
SenseDataLength = 0;
|
|
|
|
Status = SubmitInquiryCommand (
|
|
ScsiDiskDevice->ScsiIo,
|
|
EfiScsiStallSeconds (1),
|
|
NULL,
|
|
&SenseDataLength,
|
|
&HostAdapterStatus,
|
|
&TargetStatus,
|
|
(VOID *) &(ScsiDiskDevice->InquiryData),
|
|
&InquiryDataLength,
|
|
FALSE
|
|
);
|
|
if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
ParseInquiryData (ScsiDiskDevice);
|
|
return EFI_SUCCESS;
|
|
} else if (Status == EFI_NOT_READY) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// go ahead to check HostAdapterStatus and TargetStatus
|
|
// (EFI_TIMEOUT, EFI_DEVICE_ERROR)
|
|
//
|
|
Status = CheckHostAdapterStatus (HostAdapterStatus);
|
|
if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_DEVICE_ERROR) {
|
|
//
|
|
// reset the scsi channel
|
|
//
|
|
ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = CheckTargetStatus (TargetStatus);
|
|
if (Status == EFI_NOT_READY) {
|
|
//
|
|
// reset the scsi device
|
|
//
|
|
ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_DEVICE_ERROR) {
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// if goes here, meant SubmitInquiryCommand() failed.
|
|
// if ScsiDiskRequestSenseKeys() succeeds at last,
|
|
// better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)
|
|
//
|
|
MaxRetry = 3;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
|
|
Status = ScsiDiskRequestSenseKeys (
|
|
ScsiDiskDevice,
|
|
NeedRetry,
|
|
&SenseDataArray,
|
|
&NumberOfSenseKeys,
|
|
TRUE
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (!*NeedRetry) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
//
|
|
// ScsiDiskRequestSenseKeys() failed after several rounds of retry.
|
|
// set *NeedRetry = FALSE to avoid the outside caller try again.
|
|
//
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskTestUnitReady (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
BOOLEAN *NeedRetry,
|
|
EFI_SCSI_SENSE_DATA **SenseDataArray,
|
|
UINTN *NumberOfSenseKeys
|
|
)
|
|
// TODO: function comment should start with '/*++'
|
|
/*
|
|
When Test Unit Ready command succeeds,
|
|
retrieve Sense Keys via Request Sense;
|
|
When Test Unit Ready command encounters any error caused by host adapter or
|
|
target, return error without retrieving Sense Keys.
|
|
*/
|
|
// TODO: function comment should end with '--*/'
|
|
// TODO: function comment is missing 'Routine Description:'
|
|
// TODO: function comment is missing 'Arguments:'
|
|
// TODO: function comment is missing 'Returns:'
|
|
// TODO: ScsiDiskDevice - add argument and description to function comment
|
|
// TODO: NeedRetry - add argument and description to function comment
|
|
// TODO: SenseDataArray - add argument and description to function comment
|
|
// TODO: NumberOfSenseKeys - add argument and description to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 SenseDataLength;
|
|
UINT8 HostAdapterStatus;
|
|
UINT8 TargetStatus;
|
|
UINT8 Index;
|
|
UINT8 MaxRetry;
|
|
|
|
SenseDataLength = 0;
|
|
*NumberOfSenseKeys = 0;
|
|
|
|
//
|
|
// Parameter 3 and 4: do not require sense data, retrieve it when needed.
|
|
//
|
|
Status = SubmitTestUnitReadyCommand (
|
|
ScsiDiskDevice->ScsiIo,
|
|
EfiScsiStallSeconds (1),
|
|
NULL,
|
|
&SenseDataLength,
|
|
&HostAdapterStatus,
|
|
&TargetStatus
|
|
);
|
|
if (Status == EFI_NOT_READY) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// go ahead to check HostAdapterStatus and TargetStatus
|
|
//
|
|
Status = CheckHostAdapterStatus (HostAdapterStatus);
|
|
if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_DEVICE_ERROR) {
|
|
//
|
|
// reset the scsi channel
|
|
//
|
|
ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = CheckTargetStatus (TargetStatus);
|
|
if (Status == EFI_NOT_READY) {
|
|
//
|
|
// reset the scsi device
|
|
//
|
|
ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_DEVICE_ERROR) {
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
MaxRetry = 3;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
|
|
Status = ScsiDiskRequestSenseKeys (
|
|
ScsiDiskDevice,
|
|
NeedRetry,
|
|
SenseDataArray,
|
|
NumberOfSenseKeys,
|
|
FALSE
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (!*NeedRetry) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
//
|
|
// ScsiDiskRequestSenseKeys() failed after several rounds of retry.
|
|
// set *NeedRetry = FALSE to avoid the outside caller try again.
|
|
//
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DetectMediaParsingSenseKeys (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
EFI_SCSI_SENSE_DATA *SenseData,
|
|
UINTN NumberOfSenseKeys,
|
|
UINTN *Action
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
SenseData - TODO: add argument description
|
|
NumberOfSenseKeys - TODO: add argument description
|
|
Action - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN RetryLater;
|
|
|
|
//
|
|
// Default is to read capacity, unless..
|
|
//
|
|
*Action = ACTION_READ_CAPACITY;
|
|
|
|
if (NumberOfSenseKeys == 0) {
|
|
*Action = ACTION_NO_ACTION;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
|
|
//
|
|
// No Sense Key returned from last submitted command
|
|
//
|
|
*Action = ACTION_NO_ACTION;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
|
|
ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
|
|
ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
|
|
*Action = ACTION_NO_ACTION;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
|
|
ScsiDiskDevice->BlkIo.Media->MediaId++;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
|
|
ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
|
|
ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
|
|
if (RetryLater) {
|
|
*Action = ACTION_RETRY_COMMAND_LATER;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskReadCapacity (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
BOOLEAN *NeedRetry,
|
|
EFI_SCSI_SENSE_DATA **SenseDataArray,
|
|
UINTN *NumberOfSenseKeys
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
NeedRetry - TODO: add argument description
|
|
SenseDataArray - TODO: add argument description
|
|
NumberOfSenseKeys - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_DISK_CAPACITY_DATA CapacityData;
|
|
UINT32 DataLength;
|
|
UINT8 HostAdapterStatus;
|
|
UINT8 TargetStatus;
|
|
EFI_STATUS CommandStatus;
|
|
EFI_STATUS Status;
|
|
UINT8 Index;
|
|
UINT8 MaxRetry;
|
|
UINT8 SenseDataLength;
|
|
|
|
SenseDataLength = 0;
|
|
ZeroMem (&CapacityData, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
|
|
DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
|
|
|
|
*NumberOfSenseKeys = 0;
|
|
*NeedRetry = FALSE;
|
|
//
|
|
// submit Read Capacity Command. in this call,not request sense data
|
|
//
|
|
CommandStatus = SubmitReadCapacityCommand (
|
|
ScsiDiskDevice->ScsiIo,
|
|
EfiScsiStallSeconds (1),
|
|
NULL,
|
|
&SenseDataLength,
|
|
&HostAdapterStatus,
|
|
&TargetStatus,
|
|
(VOID *) &CapacityData,
|
|
&DataLength,
|
|
FALSE
|
|
);
|
|
if (CommandStatus == EFI_SUCCESS) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
GetMediaInfo (ScsiDiskDevice, &CapacityData);
|
|
return EFI_SUCCESS;
|
|
} else if (CommandStatus == EFI_NOT_READY) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
|
|
//
|
|
// no need to check HostAdapterStatus and TargetStatus
|
|
//
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// go ahead to check HostAdapterStatus and TargetStatus
|
|
// (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
|
|
//
|
|
|
|
Status = CheckHostAdapterStatus (HostAdapterStatus);
|
|
if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_DEVICE_ERROR) {
|
|
//
|
|
// reset the scsi channel
|
|
//
|
|
ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = CheckTargetStatus (TargetStatus);
|
|
if (Status == EFI_NOT_READY) {
|
|
//
|
|
// reset the scsi device
|
|
//
|
|
ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_DEVICE_ERROR) {
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// if goes here, meant SubmitReadCapacityCommand() failed.
|
|
// if ScsiDiskRequestSenseKeys() succeeds at last,
|
|
// better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)
|
|
//
|
|
MaxRetry = 3;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
|
|
Status = ScsiDiskRequestSenseKeys (
|
|
ScsiDiskDevice,
|
|
NeedRetry,
|
|
SenseDataArray,
|
|
NumberOfSenseKeys,
|
|
TRUE
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
*NeedRetry = TRUE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (!*NeedRetry) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
//
|
|
// ScsiDiskRequestSenseKeys() failed after several rounds of retry.
|
|
// set *NeedRetry = FALSE to avoid the outside caller try again.
|
|
//
|
|
*NeedRetry = FALSE;
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
EFI_STATUS
|
|
CheckHostAdapterStatus (
|
|
UINT8 HostAdapterStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
HostAdapterStatus - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_TIMEOUT - TODO: Add description for return value
|
|
EFI_NOT_READY - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
switch (HostAdapterStatus) {
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK:
|
|
return EFI_SUCCESS;
|
|
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT:
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
|
|
return EFI_TIMEOUT;
|
|
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_PARITY_ERROR:
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_RESET:
|
|
return EFI_NOT_READY;
|
|
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_FREE:
|
|
case EFI_SCSI_IO_STATUS_HOST_ADAPTER_PHASE_ERROR:
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
default:
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
CheckTargetStatus (
|
|
UINT8 TargetStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
TargetStatus - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_NOT_READY - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
switch (TargetStatus) {
|
|
case EFI_SCSI_IO_STATUS_TARGET_GOOD:
|
|
case EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION:
|
|
case EFI_SCSI_IO_STATUS_TARGET_CONDITION_MET:
|
|
return EFI_SUCCESS;
|
|
|
|
case EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE:
|
|
case EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
|
|
case EFI_SCSI_IO_STATUS_TARGET_BUSY:
|
|
case EFI_SCSI_IO_STATUS_TARGET_COMMOND_TERMINATED:
|
|
case EFI_SCSI_IO_STATUS_TARGET_QUEUE_FULL:
|
|
return EFI_NOT_READY;
|
|
|
|
case EFI_SCSI_IO_STATUS_TARGET_RESERVATION_CONFLICT:
|
|
return EFI_DEVICE_ERROR;
|
|
break;
|
|
|
|
default:
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskRequestSenseKeys (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
BOOLEAN *NeedRetry,
|
|
EFI_SCSI_SENSE_DATA **SenseDataArray,
|
|
UINTN *NumberOfSenseKeys,
|
|
BOOLEAN AskResetIfError
|
|
)
|
|
// TODO: function comment should start with '/*++'
|
|
/*
|
|
Retrieve all sense keys from the device.
|
|
When encountering error during the process,
|
|
if retrieve sense keys before error encounterred,
|
|
return the sense keys with return status set to EFI_SUCCESS,
|
|
and NeedRetry set to FALSE; otherwize, return the proper return
|
|
status.
|
|
*/
|
|
// TODO: function comment should end with '--*/'
|
|
// TODO: function comment is missing 'Routine Description:'
|
|
// TODO: function comment is missing 'Arguments:'
|
|
// TODO: function comment is missing 'Returns:'
|
|
// TODO: ScsiDiskDevice - add argument and description to function comment
|
|
// TODO: NeedRetry - add argument and description to function comment
|
|
// TODO: SenseDataArray - add argument and description to function comment
|
|
// TODO: NumberOfSenseKeys - add argument and description to function comment
|
|
// TODO: AskResetIfError - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_SCSI_SENSE_DATA *PtrSenseData;
|
|
UINT8 SenseDataLength;
|
|
BOOLEAN SenseReq;
|
|
EFI_STATUS Status;
|
|
EFI_STATUS FallStatus;
|
|
UINT8 HostAdapterStatus;
|
|
UINT8 TargetStatus;
|
|
|
|
FallStatus = EFI_SUCCESS;
|
|
SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
|
|
|
|
ZeroMem (
|
|
ScsiDiskDevice->SenseData,
|
|
sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
|
|
);
|
|
|
|
*NumberOfSenseKeys = 0;
|
|
*SenseDataArray = ScsiDiskDevice->SenseData;
|
|
PtrSenseData = ScsiDiskDevice->SenseData;
|
|
|
|
for (SenseReq = TRUE; SenseReq;) {
|
|
|
|
Status = SubmitRequestSenseCommand (
|
|
ScsiDiskDevice->ScsiIo,
|
|
EfiScsiStallSeconds (2),
|
|
PtrSenseData,
|
|
&SenseDataLength,
|
|
&HostAdapterStatus,
|
|
&TargetStatus
|
|
);
|
|
if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
|
|
FallStatus = EFI_SUCCESS;
|
|
} else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
|
|
*NeedRetry = TRUE;
|
|
FallStatus = EFI_DEVICE_ERROR;
|
|
} else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
|
|
*NeedRetry = FALSE;
|
|
FallStatus = EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_DEVICE_ERROR) {
|
|
if (AskResetIfError) {
|
|
ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
|
|
}
|
|
|
|
FallStatus = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (EFI_ERROR (FallStatus)) {
|
|
if (*NumberOfSenseKeys != 0) {
|
|
*NeedRetry = FALSE;
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
(*NumberOfSenseKeys) += 1;
|
|
|
|
//
|
|
// no more sense key or number of sense keys exceeds predefined,
|
|
// skip the loop.
|
|
//
|
|
if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
|
|
(*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
|
|
SenseReq = FALSE;
|
|
}
|
|
|
|
PtrSenseData += 1;
|
|
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
GetMediaInfo (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
EFI_SCSI_DISK_CAPACITY_DATA *Capacity
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
Capacity - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity->LastLba3 << 24) |
|
|
(Capacity->LastLba2 << 16) |
|
|
(Capacity->LastLba1 << 8) |
|
|
Capacity->LastLba0;
|
|
|
|
ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
|
|
ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity->BlockSize3 << 24) |
|
|
(Capacity->BlockSize2 << 16) |
|
|
(Capacity->BlockSize1 << 8) |
|
|
Capacity->BlockSize0;
|
|
if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
|
|
ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
|
|
}
|
|
|
|
if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) {
|
|
ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ParseInquiryData (
|
|
SCSI_DISK_DEV *ScsiDiskDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
ScsiDiskDevice->FixedDevice = (BOOLEAN) (ScsiDiskDevice->InquiryData.RMB ? 0 : 1);
|
|
ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskReadSectors (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
VOID *Buffer,
|
|
EFI_LBA Lba,
|
|
UINTN NumberOfBlocks
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
Lba - TODO: add argument description
|
|
NumberOfBlocks - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
UINTN BlocksRemaining;
|
|
UINT32 Lba32;
|
|
UINT8 *PtrBuffer;
|
|
UINT32 BlockSize;
|
|
UINT32 ByteCount;
|
|
UINT32 MaxBlock;
|
|
UINT32 SectorCount;
|
|
UINT64 Timeout;
|
|
EFI_STATUS Status;
|
|
UINT8 Index;
|
|
UINT8 MaxRetry;
|
|
BOOLEAN NeedRetry;
|
|
EFI_SCSI_SENSE_DATA *SenseData;
|
|
UINT8 SenseDataLength;
|
|
UINTN NumberOfSenseKeys;
|
|
|
|
SenseData = NULL;
|
|
SenseDataLength = 0;
|
|
NumberOfSenseKeys = 0;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
BlocksRemaining = NumberOfBlocks;
|
|
BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
|
|
//
|
|
// limit the data bytes that can be transferred by one Read(10) Command
|
|
//
|
|
MaxBlock = 65536;
|
|
|
|
PtrBuffer = Buffer;
|
|
Lba32 = (UINT32) Lba;
|
|
|
|
while (BlocksRemaining > 0) {
|
|
|
|
if (BlocksRemaining <= MaxBlock) {
|
|
|
|
SectorCount = (UINT16) BlocksRemaining;
|
|
} else {
|
|
|
|
SectorCount = MaxBlock;
|
|
}
|
|
|
|
ByteCount = SectorCount * BlockSize;
|
|
Timeout = EfiScsiStallSeconds (2);
|
|
|
|
MaxRetry = 2;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
|
|
Status = ScsiDiskRead10 (
|
|
ScsiDiskDevice,
|
|
&NeedRetry,
|
|
&SenseData,
|
|
&NumberOfSenseKeys,
|
|
Timeout,
|
|
PtrBuffer,
|
|
&ByteCount,
|
|
Lba32,
|
|
SectorCount
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
if (!NeedRetry) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
}
|
|
|
|
if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// actual transferred sectors
|
|
//
|
|
SectorCount = ByteCount / BlockSize;
|
|
|
|
Lba32 += SectorCount;
|
|
PtrBuffer = PtrBuffer + SectorCount * BlockSize;
|
|
BlocksRemaining -= SectorCount;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskWriteSectors (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
VOID *Buffer,
|
|
EFI_LBA Lba,
|
|
UINTN NumberOfBlocks
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
Lba - TODO: add argument description
|
|
NumberOfBlocks - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_DEVICE_ERROR - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
UINTN BlocksRemaining;
|
|
UINT32 Lba32;
|
|
UINT8 *PtrBuffer;
|
|
UINT32 BlockSize;
|
|
UINT32 ByteCount;
|
|
UINT32 MaxBlock;
|
|
UINT32 SectorCount;
|
|
UINT64 Timeout;
|
|
EFI_STATUS Status;
|
|
UINT8 Index;
|
|
UINT8 MaxRetry;
|
|
BOOLEAN NeedRetry;
|
|
EFI_SCSI_SENSE_DATA *SenseData;
|
|
UINT8 SenseDataLength;
|
|
UINTN NumberOfSenseKeys;
|
|
|
|
SenseData = NULL;
|
|
SenseDataLength = 0;
|
|
NumberOfSenseKeys = 0;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
BlocksRemaining = NumberOfBlocks;
|
|
BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
|
|
//
|
|
// limit the data bytes that can be transferred by one Write(10) Command
|
|
//
|
|
MaxBlock = 65536;
|
|
|
|
PtrBuffer = Buffer;
|
|
Lba32 = (UINT32) Lba;
|
|
|
|
while (BlocksRemaining > 0) {
|
|
|
|
if (BlocksRemaining <= MaxBlock) {
|
|
|
|
SectorCount = (UINT16) BlocksRemaining;
|
|
} else {
|
|
|
|
SectorCount = MaxBlock;
|
|
}
|
|
|
|
ByteCount = SectorCount * BlockSize;
|
|
Timeout = EfiScsiStallSeconds (2);
|
|
MaxRetry = 2;
|
|
for (Index = 0; Index < MaxRetry; Index++) {
|
|
Status = ScsiDiskWrite10 (
|
|
ScsiDiskDevice,
|
|
&NeedRetry,
|
|
&SenseData,
|
|
&NumberOfSenseKeys,
|
|
Timeout,
|
|
PtrBuffer,
|
|
&ByteCount,
|
|
Lba32,
|
|
SectorCount
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
if (!NeedRetry) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// actual transferred sectors
|
|
//
|
|
SectorCount = ByteCount / BlockSize;
|
|
|
|
Lba32 += SectorCount;
|
|
PtrBuffer = PtrBuffer + SectorCount * BlockSize;
|
|
BlocksRemaining -= SectorCount;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskRead10 (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
BOOLEAN *NeedRetry,
|
|
EFI_SCSI_SENSE_DATA **SenseDataArray,
|
|
UINTN *NumberOfSenseKeys,
|
|
UINT64 Timeout,
|
|
UINT8 *DataBuffer,
|
|
UINT32 *DataLength,
|
|
UINT32 StartLba,
|
|
UINT32 SectorSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
NeedRetry - TODO: add argument description
|
|
SenseDataArray - TODO: add argument description
|
|
NumberOfSenseKeys - TODO: add argument description
|
|
Timeout - TODO: add argument description
|
|
DataBuffer - TODO: add argument description
|
|
DataLength - TODO: add argument description
|
|
StartLba - TODO: add argument description
|
|
SectorSize - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
UINT8 SenseDataLength;
|
|
EFI_STATUS Status;
|
|
UINT8 HostAdapterStatus;
|
|
UINT8 TargetStatus;
|
|
|
|
*NeedRetry = FALSE;
|
|
*NumberOfSenseKeys = 0;
|
|
SenseDataLength = 0;
|
|
Status = SubmitRead10Command (
|
|
ScsiDiskDevice->ScsiIo,
|
|
Timeout,
|
|
NULL,
|
|
&SenseDataLength,
|
|
&HostAdapterStatus,
|
|
&TargetStatus,
|
|
DataBuffer,
|
|
DataLength,
|
|
StartLba,
|
|
SectorSize
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ScsiDiskWrite10 (
|
|
SCSI_DISK_DEV *ScsiDiskDevice,
|
|
BOOLEAN *NeedRetry,
|
|
EFI_SCSI_SENSE_DATA **SenseDataArray,
|
|
UINTN *NumberOfSenseKeys,
|
|
UINT64 Timeout,
|
|
UINT8 *DataBuffer,
|
|
UINT32 *DataLength,
|
|
UINT32 StartLba,
|
|
UINT32 SectorSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
NeedRetry - TODO: add argument description
|
|
SenseDataArray - TODO: add argument description
|
|
NumberOfSenseKeys - TODO: add argument description
|
|
Timeout - TODO: add argument description
|
|
DataBuffer - TODO: add argument description
|
|
DataLength - TODO: add argument description
|
|
StartLba - TODO: add argument description
|
|
SectorSize - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 SenseDataLength;
|
|
UINT8 HostAdapterStatus;
|
|
UINT8 TargetStatus;
|
|
|
|
*NeedRetry = FALSE;
|
|
*NumberOfSenseKeys = 0;
|
|
SenseDataLength = 0;
|
|
Status = SubmitWrite10Command (
|
|
ScsiDiskDevice->ScsiIo,
|
|
Timeout,
|
|
NULL,
|
|
&SenseDataLength,
|
|
&HostAdapterStatus,
|
|
&TargetStatus,
|
|
DataBuffer,
|
|
DataLength,
|
|
StartLba,
|
|
SectorSize
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
ScsiDiskIsNoMedia (
|
|
IN EFI_SCSI_SENSE_DATA *SenseData,
|
|
IN UINTN SenseCounts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
SenseData - TODO: add argument description
|
|
SenseCounts - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_SENSE_DATA *SensePtr;
|
|
UINTN Index;
|
|
BOOLEAN IsNoMedia;
|
|
|
|
IsNoMedia = FALSE;
|
|
SensePtr = SenseData;
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
//
|
|
// Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
|
|
// Additional Sense Code is ASC_NO_MEDIA (0x3A)
|
|
//
|
|
if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
|
|
(SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
|
|
IsNoMedia = TRUE;
|
|
}
|
|
|
|
SensePtr++;
|
|
}
|
|
|
|
return IsNoMedia;
|
|
}
|
|
|
|
BOOLEAN
|
|
ScsiDiskIsMediaError (
|
|
IN EFI_SCSI_SENSE_DATA *SenseData,
|
|
IN UINTN SenseCounts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
SenseData - TODO: add argument description
|
|
SenseCounts - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_SENSE_DATA *SensePtr;
|
|
UINTN Index;
|
|
BOOLEAN IsError;
|
|
|
|
IsError = FALSE;
|
|
SensePtr = SenseData;
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
switch (SensePtr->Sense_Key) {
|
|
|
|
case EFI_SCSI_SK_MEDIUM_ERROR:
|
|
//
|
|
// Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
|
|
//
|
|
switch (SensePtr->Addnl_Sense_Code) {
|
|
|
|
//
|
|
// fall through
|
|
//
|
|
case EFI_SCSI_ASC_MEDIA_ERR1:
|
|
|
|
//
|
|
// fall through
|
|
//
|
|
case EFI_SCSI_ASC_MEDIA_ERR2:
|
|
|
|
//
|
|
// fall through
|
|
//
|
|
case EFI_SCSI_ASC_MEDIA_ERR3:
|
|
case EFI_SCSI_ASC_MEDIA_ERR4:
|
|
IsError = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case EFI_SCSI_SK_NOT_READY:
|
|
//
|
|
// Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
|
|
//
|
|
switch (SensePtr->Addnl_Sense_Code) {
|
|
//
|
|
// Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
|
|
//
|
|
case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
|
|
IsError = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
SensePtr++;
|
|
}
|
|
|
|
return IsError;
|
|
}
|
|
|
|
BOOLEAN
|
|
ScsiDiskIsHardwareError (
|
|
IN EFI_SCSI_SENSE_DATA *SenseData,
|
|
IN UINTN SenseCounts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
SenseData - TODO: add argument description
|
|
SenseCounts - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_SENSE_DATA *SensePtr;
|
|
UINTN Index;
|
|
BOOLEAN IsError;
|
|
|
|
IsError = FALSE;
|
|
SensePtr = SenseData;
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
//
|
|
// Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
|
|
//
|
|
if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
|
|
IsError = TRUE;
|
|
}
|
|
|
|
SensePtr++;
|
|
}
|
|
|
|
return IsError;
|
|
}
|
|
|
|
BOOLEAN
|
|
ScsiDiskIsMediaChange (
|
|
IN EFI_SCSI_SENSE_DATA *SenseData,
|
|
IN UINTN SenseCounts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
SenseData - TODO: add argument description
|
|
SenseCounts - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_SENSE_DATA *SensePtr;
|
|
UINTN Index;
|
|
BOOLEAN IsMediaChanged;
|
|
|
|
IsMediaChanged = FALSE;
|
|
SensePtr = SenseData;
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
//
|
|
// Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
|
|
// Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
|
|
//
|
|
if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
|
|
(SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
|
|
IsMediaChanged = TRUE;
|
|
}
|
|
|
|
SensePtr++;
|
|
}
|
|
|
|
return IsMediaChanged;
|
|
}
|
|
|
|
BOOLEAN
|
|
ScsiDiskIsResetBefore (
|
|
IN EFI_SCSI_SENSE_DATA *SenseData,
|
|
IN UINTN SenseCounts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
SenseData - TODO: add argument description
|
|
SenseCounts - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_SENSE_DATA *SensePtr;
|
|
UINTN Index;
|
|
BOOLEAN IsResetBefore;
|
|
|
|
IsResetBefore = FALSE;
|
|
SensePtr = SenseData;
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
//
|
|
// Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
|
|
// Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
|
|
//
|
|
if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
|
|
(SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
|
|
IsResetBefore = TRUE;
|
|
}
|
|
|
|
SensePtr++;
|
|
}
|
|
|
|
return IsResetBefore;
|
|
}
|
|
|
|
BOOLEAN
|
|
ScsiDiskIsDriveReady (
|
|
IN EFI_SCSI_SENSE_DATA *SenseData,
|
|
IN UINTN SenseCounts,
|
|
OUT BOOLEAN *RetryLater
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
SenseData - TODO: add argument description
|
|
SenseCounts - TODO: add argument description
|
|
RetryLater - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_SENSE_DATA *SensePtr;
|
|
UINTN Index;
|
|
BOOLEAN IsReady;
|
|
|
|
IsReady = TRUE;
|
|
*RetryLater = FALSE;
|
|
SensePtr = SenseData;
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
switch (SensePtr->Sense_Key) {
|
|
|
|
case EFI_SCSI_SK_NOT_READY:
|
|
//
|
|
// Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
|
|
//
|
|
switch (SensePtr->Addnl_Sense_Code) {
|
|
case EFI_SCSI_ASC_NOT_READY:
|
|
//
|
|
// Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
|
|
//
|
|
switch (SensePtr->Addnl_Sense_Code_Qualifier) {
|
|
case EFI_SCSI_ASCQ_IN_PROGRESS:
|
|
//
|
|
// Additional Sense Code Qualifier is
|
|
// EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
|
|
//
|
|
IsReady = FALSE;
|
|
*RetryLater = TRUE;
|
|
break;
|
|
|
|
default:
|
|
IsReady = FALSE;
|
|
*RetryLater = FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
SensePtr++;
|
|
}
|
|
|
|
return IsReady;
|
|
}
|
|
|
|
BOOLEAN
|
|
ScsiDiskHaveSenseKey (
|
|
IN EFI_SCSI_SENSE_DATA *SenseData,
|
|
IN UINTN SenseCounts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
SenseData - TODO: add argument description
|
|
SenseCounts - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_SCSI_SENSE_DATA *SensePtr;
|
|
UINTN Index;
|
|
BOOLEAN HaveSenseKey;
|
|
|
|
if (SenseCounts == 0) {
|
|
HaveSenseKey = FALSE;
|
|
} else {
|
|
HaveSenseKey = TRUE;
|
|
}
|
|
|
|
SensePtr = SenseData;
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
//
|
|
// Sense Key is SK_NO_SENSE (0x0)
|
|
//
|
|
if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
|
|
(Index == 0)) {
|
|
HaveSenseKey = FALSE;
|
|
}
|
|
|
|
SensePtr++;
|
|
}
|
|
|
|
return HaveSenseKey;
|
|
}
|
|
|
|
VOID
|
|
ReleaseScsiDiskDeviceResources (
|
|
IN SCSI_DISK_DEV *ScsiDiskDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
ScsiDiskDevice - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
if (ScsiDiskDevice == NULL) {
|
|
return ;
|
|
}
|
|
|
|
if (ScsiDiskDevice->SenseData != NULL) {
|
|
gBS->FreePool (ScsiDiskDevice->SenseData);
|
|
ScsiDiskDevice->SenseData = NULL;
|
|
}
|
|
|
|
if (ScsiDiskDevice->ControllerNameTable != NULL) {
|
|
FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
|
|
ScsiDiskDevice->ControllerNameTable = NULL;
|
|
}
|
|
|
|
gBS->FreePool (ScsiDiskDevice);
|
|
|
|
ScsiDiskDevice = NULL;
|
|
}
|