summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c')
-rw-r--r--MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
new file mode 100644
index 0000000..dc28be8
--- /dev/null
+++ b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
@@ -0,0 +1,788 @@
+/*++
+
+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:
+
+ scsibus.c
+
+Abstract:
+
+
+Revision History
+--*/
+
+//
+// The package level header files this module uses
+//
+#include <PiDxe.h>
+
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Protocol/ScsiPassThru.h>
+#include <Protocol/ScsiIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DevicePath.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ScsiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "ScsiBus.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
+ SCSIBusDriverBindingSupported,
+ SCSIBusDriverBindingStart,
+ SCSIBusDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ The user Entry Point for module ScsiBus. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeScsiBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &gSCSIBusDriverBinding,
+ ImageHandle,
+ &gScsiBusComponentName,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SCSIBusDriverBindingSupported (
+ 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_UNSUPPORTED - add return value to function comment
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ EFI_STATUS Status;
+
+ //
+ // If RemainingDevicePath is not NULL, it should verify that the first device
+ // path node in RemainingDevicePath is an ATAPI Device path node.
+ //
+ if (RemainingDevicePath != NULL) {
+ if ((RemainingDevicePath->Type != MESSAGING_DEVICE_PATH) ||
+ (RemainingDevicePath->SubType != MSG_ATAPI_DP) ||
+ (DevicePathNodeLength (RemainingDevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // check for the existence of SCSI Pass Thru Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SCSIBusDriverBindingStart (
+ 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_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
+ UINT32 StartPun;
+ UINT64 StartLun;
+ UINT32 Pun;
+ UINT64 Lun;
+ BOOLEAN ScanOtherPuns;
+
+ StartPun = 0;
+ StartLun = 0;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ //
+ // Consume SCSI Pass Thru protocol.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **) &ScsiPassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ if (RemainingDevicePath == NULL) {
+ StartPun = 0xFFFFFFFF;
+ StartLun = 0;
+ } else {
+ ScsiPassThru->GetTargetLun (ScsiPassThru, RemainingDevicePath, &StartPun, &StartLun);
+ }
+
+ for (Pun = StartPun, ScanOtherPuns = TRUE; ScanOtherPuns;) {
+
+ if (StartPun == 0xFFFFFFFF) {
+ //
+ // Remaining Device Path is NULL, scan all the possible Puns in the
+ // SCSI Channel.
+ //
+ Status = ScsiPassThru->GetNextDevice (ScsiPassThru, &Pun, &Lun);
+ if (EFI_ERROR (Status)) {
+ //
+ // no legal Pun and Lun found any more
+ //
+ break;
+ }
+ } else {
+ //
+ // Remaining Device Path is not NULL, only scan the specified Pun.
+ //
+ Pun = StartPun;
+ Lun = StartLun;
+ ScanOtherPuns = FALSE;
+ }
+
+ //
+ // Avoid creating handle for the host adapter.
+ //
+ if (Pun == ScsiPassThru->Mode->AdapterId) {
+ continue;
+ }
+
+ //
+ // Scan for the scsi device, if it attaches to the scsi bus,
+ // then create handle and install scsi i/o protocol.
+ //
+ Status = ScsiScanCreateDevice (This, Controller, Pun, Lun, ScsiPassThru, ParentDevicePath);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SCSIBusDriverBindingStop (
+ 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
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ EFI_SCSI_IO_PROTOCOL *ScsiIo;
+ SCSI_IO_DEV *ScsiIoDevice;
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiScsiIoProtocolGuid,
+ (VOID **) &ScsiIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ ScsiIoDevice->DevicePath,
+ &gEfiScsiIoProtocolGuid,
+ &ScsiIoDevice->ScsiIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **) &ScsiPassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ gBS->FreePool (ScsiIoDevice);
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+ScsiGetDeviceType (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ OUT UINT8 *DeviceType
+ )
+/*++
+
+ Routine Description:
+ Retrieves the device type information of the SCSI Controller.
+
+ Arguments:
+ This - Protocol instance pointer.
+ DeviceType - A pointer to the device type information
+ retrieved from the SCSI Controller.
+
+ Returns:
+ EFI_SUCCESS - Retrieves the device type information successfully.
+ EFI_INVALID_PARAMETER - The DeviceType is NULL.
+--*/
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+
+ if (DeviceType == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+ *DeviceType = ScsiIoDevice->ScsiDeviceType;
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+ScsiGetDeviceLocation (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ OUT UINT32 *Target,
+ OUT UINT64 *Lun
+ )
+/*++
+ Routine Description:
+ Retrieves the device location in the SCSI channel.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Target - A pointer to the Target ID of a SCSI device
+ on the SCSI channel.
+ Lun - A pointer to the LUN of the SCSI device on
+ the SCSI channel.
+
+ Returns:
+ EFI_SUCCESS - Retrieves the device location successfully.
+ EFI_INVALID_PARAMETER - The Target or Lun is NULL.
+--*/
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+
+ if (Target == NULL || Lun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+
+ *Target = ScsiIoDevice->Pun;
+ *Lun = ScsiIoDevice->Lun;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+ScsiResetBus (
+ IN EFI_SCSI_IO_PROTOCOL *This
+ )
+/*++
+
+ Routine Description:
+ Resets the SCSI Bus that the SCSI Controller is attached to.
+
+ Arguments:
+ This - Protocol instance pointer.
+
+ Returns:
+ EFI_SUCCESS - The SCSI bus is reset successfully.
+ EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
+ EFI_UNSUPPORTED - The bus reset operation is not supported by the
+ SCSI Host Controller.
+ EFI_TIMEOUT - A timeout occurred while attempting to reset
+ the SCSI bus.
+--*/
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+
+ return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
+
+}
+
+EFI_STATUS
+EFIAPI
+ScsiResetDevice (
+ IN EFI_SCSI_IO_PROTOCOL *This
+ )
+/*++
+
+ Routine Description:
+ Resets the SCSI Controller that the device handle specifies.
+
+ Arguments:
+ This - Protocol instance pointer.
+
+
+ Returns:
+ EFI_SUCCESS - Reset the SCSI controller successfully.
+ EFI_DEVICE_ERROR - Errors are encountered when resetting the
+ SCSI Controller.
+ EFI_UNSUPPORTED - The SCSI bus does not support a device
+ reset operation.
+ EFI_TIMEOUT - A timeout occurred while attempting to
+ reset the SCSI Controller.
+--*/
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+
+ return ScsiIoDevice->ScsiPassThru->ResetTarget (
+ ScsiIoDevice->ScsiPassThru,
+ ScsiIoDevice->Pun,
+ ScsiIoDevice->Lun
+ );
+}
+
+EFI_STATUS
+EFIAPI
+ScsiExecuteSCSICommand (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Sends a SCSI Request Packet to the SCSI Controller for execution.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Packet - The SCSI request packet to send to the SCSI
+ Controller specified by the device handle.
+ Event - If the SCSI bus where the SCSI device is attached
+ does not support non-blocking I/O, then Event is
+ ignored, and blocking I/O is performed.
+ If Event is NULL, then blocking I/O is performed.
+ If Event is not NULL and non-blocking I/O is
+ supported, then non-blocking I/O is performed,
+ and Event will be signaled when the SCSI Request
+ Packet completes.
+ Returns:
+ EFI_SUCCESS - The SCSI Request Packet was sent by the host
+ successfully, and TransferLength bytes were
+ transferred to/from DataBuffer.See
+ HostAdapterStatus, TargetStatus,
+ SenseDataLength, and SenseData in that order
+ for additional status information.
+ EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
+ but the entire DataBuffer could not be transferred.
+ The actual number of bytes transferred is returned
+ in TransferLength. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+ EFI_NOT_READY - The SCSI Request Packet could not be sent because
+ there are too many SCSI Command Packets already
+ queued.The caller may retry again later.
+ EFI_DEVICE_ERROR - A device error occurred while attempting to send
+ the SCSI Request Packet. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+ EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
+ The SCSI Request Packet was not sent, so no
+ additional status information is available.
+ EFI_UNSUPPORTED - The command described by the SCSI Request Packet
+ is not supported by the SCSI initiator(i.e., SCSI
+ Host Controller). The SCSI Request Packet was not
+ sent, so no additional status information is
+ available.
+ EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
+ Request Packet to execute. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+--*/
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+ EFI_STATUS Status;
+
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *RequestPacket;
+
+ if (Packet == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+
+ RequestPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
+
+ Status = ScsiIoDevice->ScsiPassThru->PassThru (
+ ScsiIoDevice->ScsiPassThru,
+ ScsiIoDevice->Pun,
+ ScsiIoDevice->Lun,
+ RequestPacket,
+ Event
+ );
+ return Status;
+}
+
+EFI_STATUS
+ScsiScanCreateDevice (
+ EFI_DRIVER_BINDING_PROTOCOL *This,
+ EFI_HANDLE Controller,
+ UINT32 Pun,
+ UINT64 Lun,
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru,
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ Controller - TODO: add argument description
+ Pun - TODO: add argument description
+ Lun - TODO: add argument description
+ ScsiPassThru - TODO: add argument description
+ ParentDevicePath - TODO: add argument description
+
+Returns:
+
+ EFI_SUCCESS - TODO: Add description for return value
+ EFI_OUT_OF_RESOURCES - TODO: Add description for return value
+ EFI_SUCCESS - TODO: Add description for return value
+
+--*/
+{
+ EFI_STATUS Status;
+ SCSI_IO_DEV *ScsiIoDevice;
+ EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (SCSI_IO_DEV),
+ (VOID **) &ScsiIoDevice
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (ScsiIoDevice, sizeof (SCSI_IO_DEV));
+
+ ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;
+ ScsiIoDevice->ScsiPassThru = ScsiPassThru;
+ ScsiIoDevice->Pun = Pun;
+ ScsiIoDevice->Lun = Lun;
+
+ ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;
+ ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;
+ ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;
+ ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;
+ ScsiIoDevice->ScsiIo.ExecuteSCSICommand = ScsiExecuteSCSICommand;
+
+ if (!DiscoverScsiDevice (ScsiIoDevice)) {
+ gBS->FreePool (ScsiIoDevice);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Set Device Path
+ //
+ Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (
+ ScsiIoDevice->ScsiPassThru,
+ ScsiIoDevice->Pun,
+ ScsiIoDevice->Lun,
+ &ScsiDevicePath
+ );
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ gBS->FreePool (ScsiIoDevice);
+ return Status;
+ }
+
+ ScsiIoDevice->DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ ScsiDevicePath
+ );
+ //
+ // The memory space for ScsiDevicePath is allocated in
+ // ScsiPassThru->BuildDevicePath() function; It is no longer used
+ // after EfiAppendDevicePathNode,so free the memory it occupies.
+ //
+ gBS->FreePool (ScsiDevicePath);
+
+ if (ScsiIoDevice->DevicePath == NULL) {
+ gBS->FreePool (ScsiIoDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ScsiIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ ScsiIoDevice->DevicePath,
+ &gEfiScsiIoProtocolGuid,
+ &ScsiIoDevice->ScsiIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (ScsiIoDevice);
+ } else {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **) &ScsiPassThru,
+ This->DriverBindingHandle,
+ ScsiIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+DiscoverScsiDevice (
+ SCSI_IO_DEV *ScsiIoDevice
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ ScsiIoDevice - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_SCSI_INQUIRY_DATA InquiryData;
+ UINT32 InquiryDataLength;
+ EFI_SCSI_SENSE_DATA SenseData;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+
+ HostAdapterStatus = 0;
+ TargetStatus = 0;
+ //
+ // Using Inquiry command to scan for the device
+ //
+ InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
+ SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
+
+ Status = SubmitInquiryCommand (
+ &ScsiIoDevice->ScsiIo,
+ EfiScsiStallSeconds (1),
+ (VOID *) &SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) &InquiryData,
+ &InquiryDataLength,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // ParseSenseData (&SenseData,SenseDataLength);
+ //
+ return FALSE;
+ }
+ //
+ // Retrieved inquiry data successfully
+ //
+ if ((InquiryData.Peripheral_Qualifier != 0) &&
+ (InquiryData.Peripheral_Qualifier != 3)) {
+ return FALSE;
+ }
+
+ if (InquiryData.Peripheral_Qualifier == 3) {
+ if (InquiryData.Peripheral_Type != 0x1f) {
+ return FALSE;
+ }
+ }
+
+ if ((0x1e >= InquiryData.Peripheral_Type) && (InquiryData.Peripheral_Type >= 0xa)) {
+ return FALSE;
+ }
+
+ //
+ // valid device type and peripheral qualifier combination.
+ //
+ ScsiIoDevice->ScsiDeviceType = InquiryData.Peripheral_Type;
+ ScsiIoDevice->RemovableDevice = InquiryData.RMB;
+ if (InquiryData.Version == 0) {
+ ScsiIoDevice->ScsiVersion = 0;
+ } else {
+ //
+ // ANSI-approved version
+ //
+ ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x03);
+ }
+
+ return TRUE;
+}