//-------------------------------------------------------------------------
// ScsiBus.c - UEFI SCSI Bus Driver from MdeModulePkg/Bus/Scsi/ScsiBusDxe
// Extracted from HR650X BIOS, IDA port 13338, ScsiBus.efi
// Binary MD5: 7936aa1e7ccfbeea8cd5fb39b8e95fe3
// Image size: 0x37C0 bytes, 53 functions total
// Address range: 0x2C0 - 0x2856
//
// This is a UEFI Driver Binding protocol implementation for SCSI bus
// controllers. It opens either EFI_SCSI_PASS_THRU_PROTOCOL or
// EFI_EXT_SCSI_PASS_THRU_PROTOCOL on a controller handle, enumerates SCSI
// targets and LUNs via INQUIRY, and produces EFI_SCSI_IO_PROTOCOL on child
// handles for each discovered device.
//
// Key structures:
// SCSI_TARGET_DEVICE (0x30 bytes, signature 'scsi') - per-controller state
// SCSI_IO_PRIVATE_DATA (0x88 bytes, signature 'scio') - per-child/LUN state
//-------------------------------------------------------------------------
#include "ScsiBus.h"
//=============================================================================
// GUID DEFINITIONS
//=============================================================================
EFI_GUID gEfiScsiPassThruProtocolGuid =
{ 0x143B7632, 0xB81B, 0x4CB7, { 0xAB, 0xD3, 0xB6, 0x25, 0xA5, 0xB9, 0xBF, 0xFE } };
EFI_GUID gEfiExtScsiPassThruProtocolGuid =
{ 0xA59E8FCF, 0xBDA0, 0x43BB, { 0x90, 0xB1, 0xD3, 0x73, 0x2E, 0xCA, 0xA8, 0x77 } };
EFI_GUID gEfiScsiIoProtocolGuid =
{ 0x932F47E6, 0x2362, 0x4002, { 0x80, 0x3E, 0x3C, 0xD5, 0x4B, 0x13, 0x8F, 0x85 } };
EFI_GUID gEfiDevicePathProtocolGuid =
{ 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } };
EFI_GUID gEfiComponentName2ProtocolGuid =
{ 0x0167CCC4, 0xD0F7, 0x4F21, { 0xA3, 0xEF, 0x9E, 0x64, 0xB7, 0xCD, 0xCE, 0x8B } };
//=============================================================================
// GLOBAL VARIABLES
//=============================================================================
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gSystemTable = NULL;
EFI_BOOT_SERVICES *gBootServices = NULL;
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
STATIC VOID *mStatusCodeProtocol = NULL;
STATIC CHAR8 mSupportedLanguages[] = "en";
STATIC CHAR16 mDriverName[] = L"SCSI Bus Driver";
//=============================================================================
// PROTOCOL INSTANCES
//=============================================================================
EFI_DRIVER_BINDING_PROTOCOL gScsiBusDriverBinding = {
ScsiBusDriverBindingSupported,
ScsiBusDriverBindingStart,
ScsiBusDriverBindingStop,
SCSI_BUS_DRIVER_BINDING_VERSION,
NULL,
NULL
};
EFI_COMPONENT_NAME2_PROTOCOL gScsiBusComponentName2 = {
ScsiBusComponentNameGetDriverName,
ScsiBusComponentNameGetControllerName,
(CHAR8 *)"en"
};
//=============================================================================
// FORWARD DECLARATIONS FOR INTERNAL HELPERS
//=============================================================================
STATIC
EFI_STATUS_CODE_PROTOCOL *
GetStatusCodeProtocolInternal (
VOID
);
STATIC
VOID
EFIAPI
InternalAssertBreakpoint (
VOID
);
//=============================================================================
// MODULE ENTRY POINT
//=============================================================================
EFI_STATUS
EFIAPI
ScsiBusEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
gImageHandle = ImageHandle;
gSystemTable = SystemTable;
gBootServices = SystemTable->BootServices;
gRuntimeServices = SystemTable->RuntimeServices;
ASSERT (gImageHandle != NULL);
ASSERT (gSystemTable != NULL);
ASSERT (gBootServices != NULL);
ASSERT (gRuntimeServices != NULL);
// Initialize the HOB list from the system table configuration table.
// configuration table entries by scanning for gEfiHobListGuid.
// Install protocols
return ScsiBusDriverBindingEntryPoint (ImageHandle);
}
//=============================================================================
// DRIVER BINDING ENTRY POINT
//=============================================================================
EFI_STATUS
EFIAPI
ScsiBusDriverBindingEntryPoint (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
Status = gBootServices->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiDriverBindingProtocolGuid,
&gScsiBusDriverBinding,
&gEfiComponentName2ProtocolGuid,
&gScsiBusComponentName2,
NULL
);
ASSERT_EFI_ERROR (Status);
return Status;
}
//=============================================================================
// HOB LIST INITIALIZATION
//=============================================================================
STATIC VOID *mHobList = NULL;
STATIC
VOID
InitializeHobList (
VOID
)
{
UINTN Index;
EFI_CONFIGURATION_TABLE *ConfigTable;
if (mHobList == NULL && gSystemTable != NULL) {
ConfigTable = gSystemTable->ConfigurationTable;
if (ConfigTable != NULL) {
for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
if (CompareGuid (
&ConfigTable[Index].VendorGuid,
&gEfiHobListGuid
)) {
mHobList = ConfigTable[Index].VendorTable;
break;
}
}
}
if (mHobList == NULL) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
ASSERT (mHobList != NULL);
}
}
}
//=============================================================================
// DRIVER BINDING: Supported
//=============================================================================
EFI_STATUS
EFIAPI
ScsiBusDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
UINT8 TargetId[16];
BOOLEAN ExtSupported;
ZeroMem (TargetId, sizeof (TargetId));
//
// Try Extended SCSI Pass Thru first
//
Status = gBootServices->OpenProtocol (
ControllerHandle,
&gEfiExtScsiPassThruProtocolGuid,
(VOID **)&ExtScsiPassThru,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (Status == EFI_ALREADY_STARTED) {
return EFI_SUCCESS;
}
if (!EFI_ERROR (Status)) {
ExtSupported = TRUE;
if (RemainingDevicePath != NULL &&
!IsDevicePathEnd (RemainingDevicePath)) {
//
// Validate the RemainingDevicePath
//
Status = ExtScsiPassThru->GetNextTargetLun (
ExtScsiPassThru,
(UINT8 *)RemainingDevicePath,
&TargetId,
&Status
);
}
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiExtScsiPassThruProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return Status;
}
//
// Fall back to legacy SCSI Pass Thru
//
Status = gBootServices->OpenProtocol (
ControllerHandle,
&gEfiScsiPassThruProtocolGuid,
(VOID **)&ScsiPassThru,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (Status == EFI_ALREADY_STARTED) {
return EFI_SUCCESS;
}
if (!EFI_ERROR (Status)) {
if (!(RemainingDevicePath != NULL &&
!IsDevicePathEnd (RemainingDevicePath))) {
Status = EFI_UNSUPPORTED;
}
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiScsiPassThruProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
}
return Status;
}
//=============================================================================
// DRIVER BINDING: Start
//=============================================================================
EFI_STATUS
EFIAPI
ScsiBusDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
SCSI_TARGET_DEVICE *TargetDevice;
EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
UINT8 TargetId[16];
UINT64 Lun;
BOOLEAN ExtSupported;
BOOLEAN ChildFound;
EFI_HANDLE ChildHandle;
ExtSupported = FALSE;
ChildFound = FALSE;
ParentDevicePath = NULL;
ScsiPassThru = NULL;
ExtScsiPassThru = NULL;
TargetDevice = NULL;
ZeroMem (TargetId, sizeof (TargetId));
//
// Get parent device path
//
Status = gBootServices->OpenProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
(VOID **)&ParentDevicePath,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
return Status;
}
//
// Try Extended SCSI Pass Thru first
//
Status = gBootServices->OpenProtocol (
ControllerHandle,
&gEfiExtScsiPassThruProtocolGuid,
(VOID **)&ExtScsiPassThru,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
//
// Fall back to legacy SCSI Pass Thru
//
Status = gBootServices->OpenProtocol (
ControllerHandle,
&gEfiScsiPassThruProtocolGuid,
(VOID **)&ScsiPassThru,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
return Status;
}
ExtSupported = FALSE;
} else {
ExtSupported = TRUE;
}
//
// Allocate Target Device (0x30 bytes)
//
TargetDevice = (SCSI_TARGET_DEVICE *)AllocateZeroPool (sizeof (SCSI_TARGET_DEVICE));
if (TargetDevice == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Exit;
}
TargetDevice->Signature = SCSI_TARGET_DEVICE_SIGNATURE;
TargetDevice->IsExtPassThru = (UINT8)ExtSupported;
if (ExtSupported) {
TargetDevice->ExtScsiPassThru = ExtScsiPassThru;
} else {
TargetDevice->ScsiPassThru = ScsiPassThru;
}
//
// Install protocol to identify ourselves on the child handle
//
Status = gBootServices->InstallProtocolInterface (
&ChildHandle,
&gEfiScsiIoProtocolGuid,
EFI_NATIVE_INTERFACE,
TargetDevice + 1
);
if (EFI_ERROR (Status)) {
FreePool (TargetDevice);
goto Exit;
}
TargetDevice->Handle = ChildHandle;
//
// If RemainingDevicePath specifies a particular child, handle it now
//
if (RemainingDevicePath != NULL) {
if (IsDevicePathEnd (RemainingDevicePath)) {
return EFI_SUCCESS;
}
}
//
// Report SCSI bus enumeration progress
//
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE,
ParentDevicePath
);
//
// Enumerate all targets/LUNs on this channel/bus
//
Lun = 0;
ChildFound = TRUE;
do {
if (ChildFound) {
//
// Get next target/LUN from the pass-thru protocol
//
if (ExtSupported) {
Status = ExtScsiPassThru->GetNextTargetLun (
ExtScsiPassThru,
TargetId,
&Lun
);
} else {
Status = ScsiPassThru->GetNextTarget (
ScsiPassThru,
TargetId,
&Lun
);
}
}
if (Status == EFI_ALREADY_STARTED) {
break;
}
if (!EFI_ERROR (Status)) {
//
// Check if this target/LUN is valid via INQUIRY
//
Status = ScsiScanCreateDevice (
TargetDevice,
ControllerHandle,
TargetId,
Lun,
TargetDevice
);
if (Status == EFI_ALREADY_STARTED) {
break;
}
ChildFound = TRUE;
} else {
ChildFound = FALSE;
}
} while (ChildFound);
//
// Report SCSI bus enumeration complete
//
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
EFI_IO_BUS_SCSI | EFI_IOB_PC_DISABLE,
ParentDevicePath
);
return EFI_SUCCESS;
Exit:
if (ExtSupported) {
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiExtScsiPassThruProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
} else {
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiScsiPassThruProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
}
return Status;
}
//=============================================================================
// DRIVER BINDING: Stop
//=============================================================================
EFI_STATUS
EFIAPI
ScsiBusDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
)
{
EFI_STATUS Status;
UINTN Index;
BOOLEAN AllStopped;
SCSI_IO_PRIVATE_DATA *Private;
EFI_SCSI_IO_PROTOCOL *ScsiIo;
AllStopped = TRUE;
if (NumberOfChildren > 0) {
//
// Stop specific child devices
//
for (Index = 0; Index < NumberOfChildren; Index++) {
Status = gBootServices->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiScsiIoProtocolGuid,
(VOID **)&ScsiIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
AllStopped = FALSE;
continue;
}
//
// Close the pass-thru protocol from the child
//
if (ScsiIo->DeviceType & 0x80) {
// ExtScsiPassThru mode flag
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiExtScsiPassThruProtocolGuid,
This->DriverBindingHandle,
ChildHandleBuffer[Index]
);
} else {
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiScsiPassThruProtocolGuid,
This->DriverBindingHandle,
ChildHandleBuffer[Index]
);
}
//
// Uninstall the SCSI IO protocol and device path
//
gBootServices->UninstallMultipleProtocolInterfaces (
ChildHandleBuffer[Index],
&gEfiScsiIoProtocolGuid,
ScsiIo,
&gEfiDevicePathProtocolGuid,
(VOID *)((UINTN)ScsiIo + 0x78),
NULL
);
//
// Free the private data (0x88 bytes)
//
FreePool (ScsiIo);
}
return AllStopped ? EFI_SUCCESS : EFI_DEVICE_ERROR;
}
//
// Stop everything (no children specified)
//
Status = gBootServices->OpenProtocol (
ControllerHandle,
&gEfiScsiIoProtocolGuid,
(VOID **)&ScsiIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
//
// Close all protocols opened for the bus
//
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiScsiIoProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBootServices->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
//
// Uninstall our protocol identifier
//
gBootServices->UninstallProtocolInterface (
ControllerHandle,
&gEfiScsiIoProtocolGuid,
ScsiIo
);
//
// Free the SCSI_TARGET_DEVICE (embedded at start of ScsiIo)
//
FreePool (ScsiIo);
return EFI_SUCCESS;
}
//=============================================================================
// SCSI SCAN CREATE DEVICE
//=============================================================================
EFI_STATUS
ScsiScanCreateDevice (
IN SCSI_TARGET_DEVICE *TargetDevice,
IN EFI_HANDLE ControllerHandle,
IN UINT8 *TargetId,
IN UINT64 Lun,
IN SCSI_TARGET_DEVICE *ParentDevice
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
UINTN DevicePathSize;
SCSI_IO_PRIVATE_DATA *Private;
EFI_HANDLE ChildHandle;
UINTN MaxTargetId;
Private = NULL;
DevicePathNode = NULL;
ChildHandle = NULL;
//
// Build a SCSI device path node from the TargetId/Lun
//
if (TargetDevice->IsExtPassThru) {
Status = TargetDevice->ExtScsiPassThru->BuildDevicePath (
TargetDevice->ExtScsiPassThru,
TargetId,
Lun,
&DevicePathNode
);
} else {
Status = TargetDevice->ScsiPassThru->BuildDevicePath (
TargetDevice->ScsiPassThru,
(UINT8 *)&Lun,
&DevicePathNode
);
}
if (EFI_ERROR (Status) || DevicePathNode == NULL) {
return Status;
}
DevicePathSize = GetDevicePathSize (DevicePathNode);
//
// Check if a child already exists for this device path
//
Status = gBootServices->LocateDevicePath (
&gEfiDevicePathProtocolGuid,
&DevicePathNode,
&ChildHandle
);
if (!EFI_ERROR (Status) && ChildHandle != NULL) {
Status = gBootServices->OpenProtocol (
ChildHandle,
&gEfiScsiIoProtocolGuid,
(VOID **)&Private,
gImageHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (!EFI_ERROR (Status)) {
// Child already exists
FreePool (DevicePathNode);
return EFI_ALREADY_STARTED;
}
}
//
// Allocate SCSI_IO_PRIVATE_DATA (0x88 bytes)
//
Private = (SCSI_IO_PRIVATE_DATA *)AllocateZeroPool (sizeof (SCSI_IO_PRIVATE_DATA));
if (Private == NULL) {
FreePool (DevicePathNode);
return EFI_OUT_OF_RESOURCES;
}
Private->Signature = SCSI_IO_PRIVATE_DATA_SIGNATURE;
Private->IsExtPassThru = TargetDevice->IsExtPassThru;
Private->DevicePath = ParentDevice->Channel;
Private->Lun = Lun;
//
// Copy device path node to the private data's buffer
//
if (DevicePathSize > 0 && DevicePathSize <= 16) {
gBS->CopyMem (&Private->DevicePathNode[0], DevicePathNode, DevicePathSize);
}
//
// Set PassThru based on mode
//
if (TargetDevice->IsExtPassThru) {
Private->PassThru.ExtScsiPassThru = TargetDevice->ExtScsiPassThru;
Status = TargetDevice->ExtScsiPassThru->GetNextTargetLun (
TargetDevice->ExtScsiPassThru,
TargetId,
&TargetId,
&Status
);
} else {
Private->PassThru.ScsiPassThru = TargetDevice->ScsiPassThru;
//
// Get max target count for legacy mode
//
Status = TargetDevice->ScsiPassThru->GetNextTarget (
TargetDevice->ScsiPassThru,
TargetId,
&Lun
);
}
//
// Perform SCSI INQUIRY
//
if (ScsiInquiryDevice (Private)) {
//
// Install protocol interfaces on the child handle
//
Status = gBootServices->InstallMultipleProtocolInterfaces (
&ChildHandle,
&gEfiDevicePathProtocolGuid,
DevicePathNode,
&gEfiScsiIoProtocolGuid,
&Private->Handle,
NULL
);
if (!EFI_ERROR (Status)) {
Private->Handle = ChildHandle;
//
// Open protocol from parent to child
//
if (TargetDevice->IsExtPassThru) {
gBootServices->OpenProtocol (
TargetDevice->ExtScsiPassThru,
&gEfiExtScsiPassThruProtocolGuid,
(VOID **)&TargetDevice->ExtScsiPassThru,
gImageHandle,
Private->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
} else {
gBootServices->OpenProtocol (
TargetDevice->ScsiPassThru,
&gEfiScsiPassThruProtocolGuid,
(VOID **)&TargetDevice->ScsiPassThru,
gImageHandle,
Private->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
}
FreePool (DevicePathNode);
return EFI_SUCCESS;
}
} else {
Status = EFI_DEVICE_ERROR;
}
//
// Error cleanup
//
if (DevicePathNode != NULL) {
FreePool (DevicePathNode);
}
if (Private != NULL) {
FreePool (Private);
}
return Status;
}
//=============================================================================
// SCSI INQUIRY DEVICE
//=============================================================================
BOOLEAN
ScsiInquiryDevice (
IN SCSI_IO_PRIVATE_DATA *Private
)
{
EFI_STATUS Status;
EFI_SCSI_IO_SCSI_REQUEST_PACKET Packet;
UINT8 InquiryData[36];
UINT8 SenseData[2];
UINTN Retries;
BOOLEAN DevicePresent;
DevicePresent = FALSE;
ZeroMem (&Packet, sizeof (Packet));
ZeroMem (InquiryData, sizeof (InquiryData));
ZeroMem (SenseData, sizeof (SenseData));
//
// Set up INQUIRY CDB (6-byte command)
//
Packet.Cdb = InquiryData;
Packet.CdbLength = 6;
Packet.InDataBuffer = InquiryData;
Packet.InTransferLength = 36;
Packet.SenseData = SenseData;
Packet.SenseDataLength = 2;
Packet.Timeout = 30000000; // 30 seconds
for (Retries = 0; Retries < 2; Retries++) {
//
// Execute via the pass-thru protocol
//
if (Private->IsExtPassThru) {
Status = Private->PassThru.ExtScsiPassThru->PassThru (
Private->PassThru.ExtScsiPassThru,
Private->Channel,
&Private->DevicePathNode[0],
&InquiryData,
&SenseData,
&InquiryData,
36,
0,
NULL
);
} else {
Status = Private->PassThru.ScsiPassThru->PassThru (
Private->PassThru.ScsiPassThru,
&Private->DevicePathNode[0],
&InquiryData,
&SenseData,
&InquiryData,
36,
NULL
);
}
if (!EFI_ERROR (Status)) {
//
// Check peripheral qualifier (bits 7:5 of byte 0)
//
if ((InquiryData[0] & 0xE0) == 0) {
DevicePresent = TRUE;
}
break;
}
//
// If device is not ready, retry
//
if (Status != EFI_TIMEOUT && Status != EFI_NOT_READY) {
break;
}
}
return DevicePresent;
}
//=============================================================================
// COPY DEVICE PATH NODE
//=============================================================================
VOID
CopyDevicePathNode (
OUT UINT8 *Destination,
IN UINT8 *Source,
IN UINTN Length
)
{
//
// Copy the device path node fields:
// +0: Type (1 byte)
// +1: SubType (1 byte)
// +2: Length (2 bytes)
// +4-7: reserved for UEFI device path nodes
//
if (Length >= 4) {
CopyMem (Destination, Source, Length);
}
}
//=============================================================================
// EFI_SCSI_IO_PROTOCOL: GetDeviceType
//=============================================================================
EFI_STATUS
EFIAPI
ScsiIoGetDeviceType (
IN EFI_SCSI_IO_PROTOCOL *This,
OUT UINT8 *DeviceType
)
{
if (DeviceType == NULL) {
return EFI_INVALID_PARAMETER;
}
*DeviceType = This->DeviceType;
return EFI_SUCCESS;
}
//=============================================================================
// EFI_SCSI_IO_PROTOCOL: GetDeviceLocation
//=============================================================================
EFI_STATUS
EFIAPI
ScsiIoGetDeviceLocation (
IN EFI_SCSI_IO_PROTOCOL *Thiss,
IN OUT UINT8 **Target,
OUT UINT64 *Lun
)
{
if (Target == NULL || Lun == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Copy the device path node to the target buffer
//
CopyMem (*Target, This + 1, 16);
*Lun = 0; // Lun not directly available from ScsiIo protocol
return EFI_SUCCESS;
}
//=============================================================================
// EFI_SCSI_IO_PROTOCOL: ResetBus
//=============================================================================
EFI_STATUS
EFIAPI
ScsiIoResetBus (
IN EFI_SCSI_IO_PROTOCOL *This
)
{
//
// This function dispatches to the pass-thru protocol's Reset/ResetChannel.
// In the binary, it calls either ScsiPassThru->Reset() or
// ExtScsiPassThru->ResetChannel() depending on the mode.
//
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
EFI_IO_BUS_SCSI | EFI_IOB_PC_RESET,
NULL
);
return EFI_SUCCESS;
}
//=============================================================================
// EFI_SCSI_IO_PROTOCOL: ResetDevice
//=============================================================================
EFI_STATUS
EFIAPI
ScsiIoResetDevice (
IN EFI_SCSI_IO_PROTOCOL *This
)
{
//
// Resets the specific target/LUN, not the whole bus.
// Copies the device path node data and calls pass-thru reset.
//
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
EFI_IO_BUS_SCSI | EFI_IOB_PC_RESET,
NULL
);
return EFI_SUCCESS;
}
//=============================================================================
// EFI_SCSI_IO_PROTOCOL: ExecuteScsiCommand
//=============================================================================
EFI_STATUS
EFIAPI
ScsiIoExecuteScsiCommand (
IN EFI_SCSI_IO_PROTOCOL *This,
IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
IN EFI_EVENT Event OPTIONAL,
IN UINT64 *Timeout
)
{
EFI_STATUS Status;
UINT8 TargetId[16];
UINT64 Lun;
if (Packet == NULL) {
return EFI_INVALID_PARAMETER;
}
Lun = 0;
//
// Dispatch through the appropriate pass-thru protocol.
// The binary dispatches via the private data's IsExtPassThru flag.
//
Status = EFI_UNSUPPORTED;
return Status;
}
//=============================================================================
// EFI_COMPONENT_NAME2_PROTOCOL: GetDriverName
//=============================================================================
EFI_STATUS
EFIAPI
ScsiBusComponentNameGetDriverName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
if (Language == NULL || DriverName == NULL) {
return EFI_INVALID_PARAMETER;
}
*DriverName = mDriverName;
return EFI_SUCCESS;
}
//=============================================================================
// EFI_COMPONENT_NAME2_PROTOCOL: GetControllerName
//=============================================================================
EFI_STATUS
EFIAPI
ScsiBusComponentNameGetControllerName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
//
// This driver does not support per-controller names
//
return EFI_UNSUPPORTED;
}
//=============================================================================
// STATUS CODE PROTOCOL LOOKUP
//=============================================================================
STATIC
EFI_STATUS_CODE_PROTOCOL *
GetStatusCodeProtocolInternal (
VOID
)
{
EFI_STATUS Status;
if (mStatusCodeProtocol == NULL && gBootServices != NULL) {
Status = gBootServices->LocateProtocol (
&gEfiStatusCodeProtocolGuid,
NULL,
&mStatusCodeProtocol
);
if (mStatusCodeProtocol == NULL) {
//
// Try to find via handles
//
gBootServices->LocateProtocol (
&gEfiStatusCodeProtocolGuid,
NULL,
&mStatusCodeProtocol
);
}
}
return (EFI_STATUS_CODE_PROTOCOL *)mStatusCodeProtocol;
}
//=============================================================================
// DEBUG ASSERT
//=============================================================================
VOID
EFIAPI
ScsiBusDebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
//
// Debug assertion: break into debugger
//
CpuDeadLoop ();
}
//=============================================================================
// COPY MEM
//=============================================================================
VOID *
EFIAPI
ScsiBusCopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
UINT8 *D;
UINT8 *S;
if (Length == 0 || Destination == NULL || Source == NULL) {
return Destination;
}
D = (UINT8 *)Destination;
S = (UINT8 *)Source;
if (D > S && D < S + Length) {
//
// Overlapping: copy backwards
//
D += Length;
S += Length;
while (Length--) {
*--D = *--S;
}
} else {
while (Length--) {
*D++ = *S++;
}
}
return Destination;
}
//=============================================================================
// ZERO MEM
//=============================================================================
VOID
EFIAPI
ScsiBusZeroMem (
OUT VOID *Buffer,
IN UINTN Length
)
{
UINT8 *Ptr;
if (Buffer == NULL) {
return;
}
Ptr = (UINT8 *)Buffer;
while (Length--) {
*Ptr++ = 0;
}
}
//=============================================================================
// SET MEM
//=============================================================================
VOID *
EFIAPI
ScsiBusSetMem (
OUT VOID *Buffer,
IN UINTN Length,
IN UINT8 Value
)
{
UINT8 *Ptr;
if (Buffer == NULL) {
return Buffer;
}
Ptr = (UINT8 *)Buffer;
while (Length--) {
*Ptr++ = Value;
}
return Buffer;
}
//=============================================================================
// MEMORY ALLOCATION HELPERS
//=============================================================================
VOID *
AllocatePool (
IN UINTN AllocationSize
)
{
EFI_STATUS Status;
VOID *Buffer;
Status = gBootServices->AllocatePool (
EfiBootServicesData,
AllocationSize,
&Buffer
);
if (EFI_ERROR (Status) || Buffer == NULL) {
return NULL;
}
return Buffer;
}
VOID *
AllocateZeroPool (
IN UINTN AllocationSize
)
{
VOID *Buffer;
Buffer = AllocatePool (AllocationSize);
if (Buffer != NULL) {
ZeroMem (Buffer, AllocationSize);
}
return Buffer;
}
VOID
FreePool (
IN VOID *Buffer
)
{
if (Buffer != NULL) {
gBootServices->FreePool (Buffer);
}
}
//=============================================================================
// STRING UTILITIES
//=============================================================================
UINTN
AsciiStrLen (
IN CONST CHAR8 *String
)
{
UINTN Length;
if (String == NULL) {
return 0;
}
Length = 0;
while (*String != '\0') {
Length++;
String++;
}
return Length;
}
//=============================================================================
// REPORT STATUS CODE WITH DEVICE PATH
//=============================================================================
EFI_STATUS
ReportStatusCodeWithDevicePath (
IN EFI_STATUS_CODE_TYPE Type,
IN EFI_STATUS_CODE_VALUE Value,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
UINTN DevicePathSize;
if (DevicePath == NULL) {
return EFI_INVALID_PARAMETER;
}
DevicePathSize = GetDevicePathSize (DevicePath);
if (DevicePathSize == 0) {
return EFI_INVALID_PARAMETER;
}
return REPORT_STATUS_CODE (Type, Value);
}
//=============================================================================
// UNALIGNED ACCESS HELPERS (used internally)
//=============================================================================
UINT64
EFIAPI
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
if (Buffer == NULL) {
return 0;
}
return *(UINT64 *)Buffer;
}
UINT64
EFIAPI
WriteUnaligned64 (
OUT VOID *Buffer,
IN UINT64 Value
)
{
if (Buffer == NULL) {
return Value;
}
*(UINT64 *)Buffer = Value;
return Value;
}
BOOLEAN
EFIAPI
CompareUnaligned24 (
IN CONST UINT32 *A,
IN CONST UINT32 *B
)
{
if (A == NULL || B == NULL) {
return FALSE;
}
return ((*A & 0xFFFFFF) == (*B & 0xFFFFFF));
}
//=============================================================================
// PCD STRING LENGTH CHECK (from BaseLib)
//=============================================================================
#define PCD_MAX_ASCII_STRING_LENGTH 0xF4240
UINTN
AsciiStrLenSafe (
IN CONST CHAR8 *String
)
{
UINTN Length;
if (String == NULL) {
return 0;
}
Length = 0;
while (*String != '\0') {
if (Length >= PCD_MAX_ASCII_STRING_LENGTH) {
break;
}
Length++;
String++;
}
return Length;
}
INTN
AsciiStrnCmp (
IN CONST CHAR8 *FirstString,
IN CONST CHAR8 *SecondString,
IN UINTN Length
)
{
if (Length == 0) {
return 0;
}
while (*FirstString != '\0' &&
*SecondString != '\0' &&
*FirstString == *SecondString &&
Length > 1) {
FirstString++;
SecondString++;
Length--;
}
return (INTN)((UINT8)*FirstString - (UINT8)*SecondString);
}
//=============================================================================
// COPY GUID
//=============================================================================
VOID
CopyGuid (
OUT GUID *Destination,
IN CONST GUID *Source
)
{
WriteUnaligned64 ((UINT64 *)Destination, ReadUnaligned64 ((UINT64 *)Source));
WriteUnaligned64 (
(UINT64 *)((UINT8 *)Destination + 8),
ReadUnaligned64 ((UINT8 *)(Source) + 8)
);
}
//=============================================================================
// COMPARE GUID
//=============================================================================
BOOLEAN
CompareGuid (
IN CONST GUID *Guid1,
IN CONST GUID *Guid2
)
{
UINT64 Low1;
UINT64 Low2;
UINT64 High1;
UINT64 High2;
Low1 = ReadUnaligned64 ((UINT64 *)Guid1);
High1 = ReadUnaligned64 ((UINT64 *)Guid1 + 1);
Low2 = ReadUnaligned64 ((UINT64 *)Guid2);
High2 = ReadUnaligned64 ((UINT64 *)Guid2 + 1);
return (Low1 == Low2 && High1 == High2);
}
//=============================================================================
// DEVICE PATH UTILITIES
//=============================================================================
BOOLEAN
EFIAPI
IsDevicePathEnd (
IN EFI_DEVICE_PATH_PROTOCOL *Node
)
{
if (Node == NULL) {
return FALSE;
}
return (Node->Type == END_DEVICE_PATH_TYPE);
}
UINT16
EFIAPI
GetDevicePathSize (
IN EFI_DEVICE_PATH_PROTOCOL *Node
)
{
if (Node == NULL) {
return 0;
}
return *(UINT16 *)((UINT8 *)Node + 2);
}