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