X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FBus%2FScsi%2FScsiBusDxe%2FScsiBus.c;h=b1c4d207f9de8bf415b3b7a157906391dcba334e;hp=68f3683bb632cfc0cda7f1a700511c883309fdff;hb=c8ad2d7a296c851c2a91519f80dab479df0fdf46;hpb=70c94b3b6ddf1d84ddb20118d898fd7a85725386 diff --git a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c index 68f3683bb6..b1c4d207f9 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c +++ b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c @@ -1,52 +1,22 @@ -/*++ +/** @file + SCSI Bus driver that layers on every SCSI Pass Thru and + Extended SCSI Pass Thru protocol in the system. -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. +Copyright (c) 2006 - 2010, 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 -Module Name: +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - scsibus.c - -Abstract: - +**/ -Revision History ---*/ - -// -// The package level header files this module uses -// -#include - -// -// The protocols, PPI and GUID defintions for this module -// -#include -#include -#include -#include -#include -#include -// -// The Library classes this module consumes -// -#include -#include -#include -#include -#include -#include -#include -#include #include "ScsiBus.h" + EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = { SCSIBusDriverBindingSupported, SCSIBusDriverBindingStart, @@ -56,51 +26,59 @@ EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = { NULL }; +VOID *mWorkingBuffer; -// -// The ScsiBusProtocol is just used to locate ScsiBusDev -// structure in the SCSIBusDriverBindingStop(). Then we can -// Close all opened protocols and release this structure. -// -STATIC EFI_GUID mScsiBusProtocolGuid = EFI_SCSI_BUS_PROTOCOL_GUID; +/** + Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet. -STATIC VOID *WorkingBuffer; + @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET + @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET -STATIC +**/ EFI_STATUS EFIAPI ScsiioToPassThruPacket ( IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, - IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket - ) -; + OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket + ); +/** + Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet. + + @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET + @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET -STATIC +**/ EFI_STATUS EFIAPI PassThruToScsiioPacket ( IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket, - IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet - ) -; -STATIC + OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet + ); + +/** + Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0 + SCSI IO Packet. + + @param Event The instance of EFI_EVENT. + @param Context The parameter passed in. + +**/ VOID EFIAPI NotifyFunction ( - EFI_EVENT Event, - VOID *Context - ) -; + IN EFI_EVENT Event, + IN VOID *Context + ); /** 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. + @param ImageHandle The firmware allocated handle for the EFI image. + @param 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 @@ -115,21 +93,39 @@ InitializeScsiBus( // // Install driver model protocol(s). // - Status = EfiLibInstallAllDriverProtocols ( + Status = EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, &gSCSIBusDriverBinding, ImageHandle, &gScsiBusComponentName, - NULL, - NULL + &gScsiBusComponentName2 ); ASSERT_EFI_ERROR (Status); - return Status; } + +/** + Test to see if this driver supports ControllerHandle. + + This service is called by the EFI boot service ConnectController(). In order + to make drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these calling restrictions. If + any other agent wishes to call Supported() it must also follow these calling + restrictions. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to test + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver supports this device + @retval EFI_ALREADY_STARTED This driver is already running on this device + @retval other This driver does not support this device + +**/ EFI_STATUS EFIAPI SCSIBusDriverBindingSupported ( @@ -137,32 +133,21 @@ SCSIBusDriverBindingSupported ( IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) -/*++ - -Routine Description: - - Test to see if this driver supports ControllerHandle. Any ControllerHandle - that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported. - -Arguments: - - This - Protocol instance pointer. - Controller - Handle of device to test - RemainingDevicePath - Not used - -Returns: - - EFI_SUCCESS - This driver supports this device. - EFI_UNSUPPORTED - This driver does not support this device. - ---*/ - { - EFI_STATUS Status; - EFI_SCSI_PASS_THRU_PROTOCOL *PassThru; + EFI_STATUS Status; + EFI_SCSI_PASS_THRU_PROTOCOL *PassThru; EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru; + UINT64 Lun; + UINT8 *TargetId; + SCSI_TARGET_ID ScsiTargetId; + + TargetId = &ScsiTargetId.ScsiId.ExtScsi[0]; + SetMem (TargetId, TARGET_MAX_BYTES, 0xFF); + // - // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol + // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as + // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly + // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead. // Status = gBS->OpenProtocol ( Controller, @@ -172,48 +157,103 @@ Returns: Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); - + if (Status == EFI_ALREADY_STARTED) { return EFI_SUCCESS; - } - - if (EFI_ERROR (Status)) { - Status = gBS->OpenProtocol ( - Controller, - &gEfiScsiPassThruProtocolGuid, - (VOID **)&PassThru, - This->DriverBindingHandle, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - if (Status == EFI_ALREADY_STARTED) { + } else if (!EFI_ERROR(Status)) { + // + // Check if RemainingDevicePath is NULL or the End of Device Path Node, + // if yes, return EFI_SUCCESS. + // + if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) { + // + // Close protocol regardless of RemainingDevicePath validation + // + gBS->CloseProtocol ( + Controller, + &gEfiExtScsiPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); return EFI_SUCCESS; + } else { + // + // If RemainingDevicePath isn't the End of Device Path Node, check its validation + // + Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun); + // + // Close protocol regardless of RemainingDevicePath validation + // + gBS->CloseProtocol ( + Controller, + &gEfiExtScsiPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); + if (!EFI_ERROR(Status)) { + return EFI_SUCCESS; + } } - - if (EFI_ERROR (Status)) { - return Status; - } + } - gBS->CloseProtocol ( - Controller, - &gEfiScsiPassThruProtocolGuid, - This->DriverBindingHandle, - Controller - ); + // + // Come here in 2 condition: + // 1. ExtPassThru doesn't exist. + // 2. ExtPassThru exists but RemainingDevicePath is invalid. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + (VOID **)&PassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (Status == EFI_ALREADY_STARTED) { return EFI_SUCCESS; } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Test RemainingDevicePath is valid or not. + // + if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) { + Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun); + } + gBS->CloseProtocol ( - Controller, - &gEfiExtScsiPassThruProtocolGuid, - This->DriverBindingHandle, - Controller - ); - - return EFI_SUCCESS; + Controller, + &gEfiScsiPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; } + +/** + Start this driver on ControllerHandle. + + This service is called by the EFI boot service ConnectController(). In order + to make drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these calling restrictions. If + any other agent wishes to call Start() it must also follow these calling + restrictions. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to bind driver to + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle + @retval other This driver does not support this device + +**/ EFI_STATUS EFIAPI SCSIBusDriverBindingStart ( @@ -221,152 +261,180 @@ SCSIBusDriverBindingStart ( IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) -/*++ - -Routine Description: - Starting the SCSI Bus Driver - -Arguments: - This - Protocol instance pointer. - Controller - Handle of device to test - RemainingDevicePath - Not used - -Returns: - EFI_SUCCESS - This driver supports this device. - EFI_UNSUPPORTED - This driver does not support this device. - EFI_DEVICE_ERROR - This driver cannot be started due to device Error - ---*/ -// 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; - UINT64 Lun; - BOOLEAN ScanOtherPuns; - SCSI_BUS_DEVICE *ScsiBusDev; - BOOLEAN FromFirstTarget; - SCSI_TARGET_ID *ScsiTargetId; - UINT8 *TargetId; - - TargetId = NULL; - ScanOtherPuns = TRUE; + UINT64 Lun; + UINT8 *TargetId; + BOOLEAN ScanOtherPuns; + BOOLEAN FromFirstTarget; + BOOLEAN ExtScsiSupport; + EFI_STATUS Status; + EFI_STATUS DevicePathStatus; + EFI_STATUS PassThruStatus; + SCSI_BUS_DEVICE *ScsiBusDev; + SCSI_TARGET_ID ScsiTargetId; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface; + EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface; + EFI_SCSI_BUS_PROTOCOL *BusIdentify; + + TargetId = NULL; + ScanOtherPuns = TRUE; FromFirstTarget = FALSE; - // - // Allocate SCSI_BUS_DEVICE structure - // - ScsiBusDev = NULL; - ScsiBusDev = AllocateZeroPool (sizeof (SCSI_BUS_DEVICE)); - if (ScsiBusDev == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - ScsiTargetId = NULL; - ScsiTargetId = AllocateZeroPool (sizeof (SCSI_TARGET_ID)); - if (ScsiTargetId == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - TargetId = &ScsiTargetId->ScsiId.ExtScsi[0]; + ExtScsiSupport = FALSE; + PassThruStatus = EFI_SUCCESS; - Status = gBS->OpenProtocol ( - Controller, - &gEfiDevicePathProtocolGuid, - (VOID **) &(ScsiBusDev->DevicePath), - This->DriverBindingHandle, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { - gBS->FreePool (ScsiBusDev); - return Status; + TargetId = &ScsiTargetId.ScsiId.ExtScsi[0]; + SetMem (TargetId, TARGET_MAX_BYTES, 0xFF); + + DevicePathStatus = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) { + return DevicePathStatus; } // - // First consume Extended SCSI Pass Thru protocol, if fail, then consume - // SCSI Pass Thru protocol + // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as + // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly + // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead. // Status = gBS->OpenProtocol ( Controller, &gEfiExtScsiPassThruProtocolGuid, - (VOID **) &(ScsiBusDev->ExtScsiInterface), + (VOID **) &ExtScsiInterface, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); - if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + // + // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead. + // + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { Status = gBS->OpenProtocol ( Controller, &gEfiScsiPassThruProtocolGuid, - (VOID **) &(ScsiBusDev->ScsiInterface), + (VOID **) &ScsiInterface, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); - if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { - gBS->CloseProtocol ( - Controller, - &gEfiDevicePathProtocolGuid, - This->DriverBindingHandle, - Controller - ); - gBS->FreePool (ScsiBusDev); + // + // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time. + // + if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { + if (!EFI_ERROR(DevicePathStatus)) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } return Status; } - DEBUG ((EFI_D_INFO, "Open Scsi Pass Thrugh Protocol\n")); - ScsiBusDev->ExtScsiSupport = FALSE; } else { - DEBUG ((EFI_D_INFO, "Open Extended Scsi Pass Thrugh Protocol\n")); - ScsiBusDev->ExtScsiSupport = TRUE; + // + // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol + // with BY_DRIVER if it is also present on the handle. The intent is to prevent + // another SCSI Bus Driver to work on the same host handle. + // + ExtScsiSupport = TRUE; + PassThruStatus = gBS->OpenProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + (VOID **) &ScsiInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); } - - ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE; - // - // Attach EFI_SCSI_BUS_PROTOCOL to controller handle - // - Status = gBS->InstallProtocolInterface ( - &Controller, - &mScsiBusProtocolGuid, - EFI_NATIVE_INTERFACE, - &ScsiBusDev->BusIdentify - ); - - if (EFI_ERROR (Status)) { - gBS->CloseProtocol ( - Controller, - &gEfiDevicePathProtocolGuid, - This->DriverBindingHandle, - Controller - ); + + if (Status != EFI_ALREADY_STARTED) { + // + // Go through here means either ExtPassThru or PassThru Protocol is successfully opened + // on this handle for this time. Then construct Host controller private data. + // + ScsiBusDev = NULL; + ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE)); + if (ScsiBusDev == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE; + ScsiBusDev->ExtScsiSupport = ExtScsiSupport; + ScsiBusDev->DevicePath = ParentDevicePath; if (ScsiBusDev->ExtScsiSupport) { - gBS->CloseProtocol ( - Controller, - &gEfiExtScsiPassThruProtocolGuid, - This->DriverBindingHandle, - Controller - ); + ScsiBusDev->ExtScsiInterface = ExtScsiInterface; } else { - gBS->CloseProtocol ( - Controller, - &gEfiScsiPassThruProtocolGuid, - This->DriverBindingHandle, - Controller - ); + ScsiBusDev->ScsiInterface = ScsiInterface; } - gBS->FreePool (ScsiBusDev); - return Status; + + // + // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be + // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru + // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol. + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiCallerIdGuid, + EFI_NATIVE_INTERFACE, + &ScsiBusDev->BusIdentify + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + } else { + // + // Go through here means Start() is re-invoked again, nothing special is required to do except + // picking up Host controller private information. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &BusIdentify, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify); } + Lun = 0; if (RemainingDevicePath == NULL) { - SetMem (ScsiTargetId, TARGET_MAX_BYTES,0xFF); - Lun = 0; + // + // If RemainingDevicePath is NULL, + // must enumerate all SCSI devices anyway + // FromFirstTarget = TRUE; - } else { + } else if (!IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath isn't the End of Device Path Node, + // only scan the specified device by RemainingDevicePath + // if (ScsiBusDev->ExtScsiSupport) { - ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun); + Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun); } else { - ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId->ScsiId.Scsi, &Lun); + Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun); + } + + if (EFI_ERROR (Status)) { + return Status; } + } else { + // + // If RemainingDevicePath is the End of Device Path Node, + // skip enumerate any device and return EFI_SUCESSS + // + ScanOtherPuns = FALSE; } while(ScanOtherPuns) { @@ -378,7 +446,7 @@ Returns: if (ScsiBusDev->ExtScsiSupport) { Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun); } else { - Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId->ScsiId.Scsi, &Lun); + Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun); } if (EFI_ERROR (Status)) { // @@ -393,11 +461,11 @@ Returns: // Avoid creating handle for the host adapter. // if (ScsiBusDev->ExtScsiSupport) { - if ((ScsiTargetId->ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) { + if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) { continue; } } else { - if ((ScsiTargetId->ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) { + if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) { continue; } } @@ -405,11 +473,61 @@ Returns: // 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, ScsiTargetId, Lun, ScsiBusDev); + Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev); + } + return EFI_SUCCESS; + +ErrorExit: + + if (ScsiBusDev != NULL) { + FreePool (ScsiBusDev); + } + + if (ExtScsiSupport) { + gBS->CloseProtocol ( + Controller, + &gEfiExtScsiPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); + if (!EFI_ERROR (PassThruStatus)) { + gBS->CloseProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + } else { + gBS->CloseProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); } return Status; } +/** + Stop this driver on ControllerHandle. + + This service is called by the EFI boot service DisconnectController(). + In order to make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() must follow these + calling restrictions. If any other agent wishes to call Stop() it must also + follow these calling restrictions. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ EFI_STATUS EFIAPI SCSIBusDriverBindingStop ( @@ -418,22 +536,6 @@ SCSIBusDriverBindingStop ( 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; @@ -450,13 +552,13 @@ SCSIBusDriverBindingStop ( // Status = gBS->OpenProtocol ( Controller, - &mScsiBusProtocolGuid, + &gEfiCallerIdGuid, (VOID **) &Scsidentifier, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); - + if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } @@ -468,20 +570,34 @@ SCSIBusDriverBindingStop ( // gBS->UninstallProtocolInterface ( Controller, - &mScsiBusProtocolGuid, + &gEfiCallerIdGuid, &ScsiBusDev->BusIdentify ); - + // // Close the bus driver // if (ScsiBusDev->ExtScsiSupport) { + // + // Close ExtPassThru Protocol from this controller handle + // gBS->CloseProtocol ( Controller, &gEfiExtScsiPassThruProtocolGuid, This->DriverBindingHandle, Controller ); + // + // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER. + // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle. + // So Stop() needs to try to close PassThru if present here. + // + gBS->CloseProtocol ( + Controller, + &gEfiScsiPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); } else { gBS->CloseProtocol ( Controller, @@ -497,7 +613,7 @@ SCSIBusDriverBindingStop ( This->DriverBindingHandle, Controller ); - gBS->FreePool (ScsiBusDev); + FreePool (ScsiBusDev); return EFI_SUCCESS; } @@ -553,7 +669,7 @@ SCSIBusDriverBindingStop ( gBS->OpenProtocol ( Controller, &gEfiExtScsiPassThruProtocolGuid, - &(EFI_EXT_SCSI_PASS_THRU_PROTOCOL*)ScsiPassThru, + &ScsiPassThru, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER @@ -562,14 +678,14 @@ SCSIBusDriverBindingStop ( gBS->OpenProtocol ( Controller, &gEfiScsiPassThruProtocolGuid, - &(EFI_SCSI_PASS_THRU_PROTOCOL*)ScsiPassThru, + &ScsiPassThru, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } } else { - gBS->FreePool (ScsiIoDevice); + FreePool (ScsiIoDevice); } } @@ -580,26 +696,24 @@ SCSIBusDriverBindingStop ( return EFI_SUCCESS; } + +/** + Retrieves the device type information of the SCSI Controller. + + @param This Protocol instance pointer. + @param DeviceType A pointer to the device type information retrieved from + the SCSI Controller. + + @retval EFI_SUCCESS Retrieves the device type information successfully. + @retval EFI_INVALID_PARAMETER The DeviceType is NULL. + +**/ 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; @@ -612,6 +726,20 @@ ScsiGetDeviceType ( return EFI_SUCCESS; } + +/** + Retrieves the device location in the SCSI channel. + + @param This Protocol instance pointer. + @param Target A pointer to the Target ID of a SCSI device + on the SCSI channel. + @param Lun A pointer to the LUN of the SCSI device on + the SCSI channel. + + @retval EFI_SUCCESS Retrieves the device location successfully. + @retval EFI_INVALID_PARAMETER The Target or Lun is NULL. + +**/ EFI_STATUS EFIAPI ScsiGetDeviceLocation ( @@ -619,21 +747,6 @@ ScsiGetDeviceLocation ( IN OUT UINT8 **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; @@ -641,36 +754,32 @@ ScsiGetDeviceLocation ( return EFI_INVALID_PARAMETER; } - ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); + ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES); - *Lun = ScsiIoDevice->Lun; + *Lun = ScsiIoDevice->Lun; return EFI_SUCCESS; } +/** + Resets the SCSI Bus that the SCSI Controller is attached to. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The SCSI bus is reset successfully. + @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus. + @retval EFI_UNSUPPORTED The bus reset operation is not supported by the + SCSI Host Controller. + @retval EFI_TIMEOUT A timeout occurred while attempting to reset + the SCSI bus. +**/ 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; @@ -683,31 +792,25 @@ ScsiResetBus ( } } + +/** + Resets the SCSI Controller that the device handle specifies. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS Reset the SCSI controller successfully. + @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller. + @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation. + @retval EFI_TIMEOUT A timeout occurred while attempting to reset the + SCSI Controller. +**/ 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; + SCSI_IO_DEV *ScsiIoDevice; UINT8 Target[TARGET_MAX_BYTES]; ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); @@ -729,66 +832,64 @@ ScsiResetDevice ( } } + +/** + Sends a SCSI Request Packet to the SCSI Controller for execution. + + @param This Protocol instance pointer. + @param CommandPacket The SCSI request packet to send to the SCSI + Controller specified by the device handle. + @param 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. + + @retval 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. + @retval EFI_BAD_BUFFER_SIZE 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. + @retval 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. + @retval 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. + @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid. + The SCSI Request Packet was not sent, so no + additional status information is available. + @retval 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. + @retval 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. +**/ EFI_STATUS EFIAPI ScsiExecuteSCSICommand ( - IN EFI_SCSI_IO_PROTOCOL *This, - IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, - IN EFI_EVENT Event OPTIONAL + 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; + SCSI_IO_DEV *ScsiIoDevice; + EFI_STATUS Status; UINT8 Target[TARGET_MAX_BYTES]; EFI_EVENT PacketEvent; EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket; @@ -802,7 +903,7 @@ ScsiExecuteSCSICommand ( ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES); - + if (ScsiIoDevice->ExtScsiSupport) { ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet; Status = ScsiIoDevice->ExtScsiPassThru->PassThru ( @@ -814,26 +915,22 @@ ScsiExecuteSCSICommand ( ); } else { - Status = gBS->AllocatePool ( - EfiBootServicesData, - sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET), - (VOID**)&WorkingBuffer - ); + mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET)); - if (EFI_ERROR (Status)) { + if (mWorkingBuffer == NULL) { return EFI_DEVICE_ERROR; } // - // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET. + // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET. // - Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)WorkingBuffer); + Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer); if (EFI_ERROR(Status)) { - gBS->FreePool(WorkingBuffer); + FreePool(mWorkingBuffer); return Status; } - if ((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) && (Event != NULL)) { + if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) { EventData.Data1 = (VOID*)Packet; EventData.Data2 = Event; // @@ -847,24 +944,24 @@ ScsiExecuteSCSICommand ( &PacketEvent ); if (EFI_ERROR(Status)) { - gBS->FreePool(WorkingBuffer); + FreePool(mWorkingBuffer); return Status; } - + Status = ScsiIoDevice->ScsiPassThru->PassThru ( ScsiIoDevice->ScsiPassThru, ScsiIoDevice->Pun.ScsiId.Scsi, ScsiIoDevice->Lun, - WorkingBuffer, + mWorkingBuffer, PacketEvent ); if (EFI_ERROR(Status)) { - gBS->FreePool(WorkingBuffer); + FreePool(mWorkingBuffer); gBS->CloseEvent(PacketEvent); return Status; } - + } else { // // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert @@ -874,69 +971,111 @@ ScsiExecuteSCSICommand ( ScsiIoDevice->ScsiPassThru, ScsiIoDevice->Pun.ScsiId.Scsi, ScsiIoDevice->Lun, - WorkingBuffer, + mWorkingBuffer, Event ); if (EFI_ERROR(Status)) { - gBS->FreePool(WorkingBuffer); + FreePool(mWorkingBuffer); return Status; } - PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)WorkingBuffer,Packet); + PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet); // // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet, - // free WorkingBuffer. + // free mWorkingBuffer. // - gBS->FreePool(WorkingBuffer); + FreePool(mWorkingBuffer); } } return Status; } -EFI_STATUS -EFIAPI -ScsiScanCreateDevice ( - EFI_DRIVER_BINDING_PROTOCOL *This, - EFI_HANDLE Controller, - SCSI_TARGET_ID *TargetId, - UINT64 Lun, - SCSI_BUS_DEVICE *ScsiBusDev - ) -/*++ - -Routine Description: +/** Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it. -Arguments: - - This - Protocol instance pointer - Controller - Controller handle - Pun - The Pun of the SCSI device on the SCSI channel. - Lun - The Lun of the SCSI device on the SCSI channel. - ScsiBusDev - The pointer of SCSI_BUS_DEVICE - -Returns: + @param This Protocol instance pointer + @param Controller Controller handle + @param TargetId Tartget to be scanned + @param Lun The Lun of the SCSI device on the SCSI channel. + @param ScsiBusDev The pointer of SCSI_BUS_DEVICE - EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it. - EFI_OUT_OF_RESOURCES - Fail to discover the device. + @retval EFI_SUCCESS Successfully to discover the device and attach + ScsiIoProtocol to it. + @retval EFI_OUT_OF_RESOURCES Fail to discover the device. ---*/ +**/ +EFI_STATUS +EFIAPI +ScsiScanCreateDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN SCSI_TARGET_ID *TargetId, + IN UINT64 Lun, + IN OUT SCSI_BUS_DEVICE *ScsiBusDev + ) { EFI_STATUS Status; SCSI_IO_DEV *ScsiIoDevice; EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; + EFI_HANDLE DeviceHandle; - Status = gBS->AllocatePool ( - EfiBootServicesData, - sizeof (SCSI_IO_DEV), - (VOID **) &ScsiIoDevice - ); - if (EFI_ERROR (Status)) { + DevicePath = NULL; + RemainingDevicePath = NULL; + ScsiDevicePath = NULL; + ScsiIoDevice = NULL; + + // + // Build Device Path + // + if (ScsiBusDev->ExtScsiSupport){ + Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath ( + ScsiBusDev->ExtScsiInterface, + &TargetId->ScsiId.ExtScsi[0], + Lun, + &ScsiDevicePath + ); + } else { + Status = ScsiBusDev->ScsiInterface->BuildDevicePath ( + ScsiBusDev->ScsiInterface, + TargetId->ScsiId.Scsi, + Lun, + &ScsiDevicePath + ); + } + + if (EFI_ERROR(Status)) { return Status; } - ZeroMem (ScsiIoDevice, sizeof (SCSI_IO_DEV)); + DevicePath = AppendDevicePathNode ( + ScsiBusDev->DevicePath, + ScsiDevicePath + ); + + if (DevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + DeviceHandle = NULL; + RemainingDevicePath = DevicePath; + Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle); + if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) { + // + // The device has been started, directly return to fast boot. + // + Status = EFI_ALREADY_STARTED; + goto ErrorExit; + } + + ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV)); + if (ScsiIoDevice == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE; CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES); @@ -959,55 +1098,13 @@ Returns: ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice; ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand; - if (!DiscoverScsiDevice (ScsiIoDevice)) { - gBS->FreePool (ScsiIoDevice); - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; } - // - // Set Device Path - // - if (ScsiIoDevice->ExtScsiSupport){ - Status = ScsiIoDevice->ExtScsiPassThru->BuildDevicePath ( - ScsiIoDevice->ExtScsiPassThru, - &ScsiIoDevice->Pun.ScsiId.ExtScsi[0], - ScsiIoDevice->Lun, - &ScsiDevicePath - ); - if (Status == EFI_OUT_OF_RESOURCES) { - gBS->FreePool (ScsiIoDevice); - return Status; - } - } else { - Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath ( - ScsiIoDevice->ScsiPassThru, - ScsiIoDevice->Pun.ScsiId.Scsi, - ScsiIoDevice->Lun, - &ScsiDevicePath - ); - if (Status == EFI_OUT_OF_RESOURCES) { - gBS->FreePool (ScsiIoDevice); - return Status; - } - } - - ScsiIoDevice->DevicePath = AppendDevicePathNode ( - ScsiBusDev->DevicePath, - 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); + ScsiIoDevice->DevicePath = DevicePath; - if (ScsiIoDevice->DevicePath == NULL) { - gBS->FreePool (ScsiIoDevice); - return EFI_OUT_OF_RESOURCES; - } - Status = gBS->InstallMultipleProtocolInterfaces ( &ScsiIoDevice->Handle, &gEfiDevicePathProtocolGuid, @@ -1017,53 +1114,64 @@ Returns: NULL ); if (EFI_ERROR (Status)) { - gBS->FreePool (ScsiIoDevice); - return EFI_OUT_OF_RESOURCES; + goto ErrorExit; } else { if (ScsiBusDev->ExtScsiSupport) { gBS->OpenProtocol ( - Controller, - &gEfiExtScsiPassThruProtocolGuid, - (VOID **) &(ScsiBusDev->ExtScsiInterface), - This->DriverBindingHandle, - ScsiIoDevice->Handle, - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ); + Controller, + &gEfiExtScsiPassThruProtocolGuid, + (VOID **) &(ScsiBusDev->ExtScsiInterface), + This->DriverBindingHandle, + ScsiIoDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); } else { gBS->OpenProtocol ( - Controller, - &gEfiScsiPassThruProtocolGuid, - (VOID **) &(ScsiBusDev->ScsiInterface), - This->DriverBindingHandle, - ScsiIoDevice->Handle, - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ); + Controller, + &gEfiScsiPassThruProtocolGuid, + (VOID **) &(ScsiBusDev->ScsiInterface), + This->DriverBindingHandle, + ScsiIoDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); } } return EFI_SUCCESS; -} -BOOLEAN -EFIAPI -DiscoverScsiDevice ( - SCSI_IO_DEV *ScsiIoDevice - ) -/*++ +ErrorExit: + + // + // The memory space for ScsiDevicePath is allocated in + // ScsiPassThru->BuildDevicePath() function; It is no longer used + // after AppendDevicePathNode,so free the memory it occupies. + // + FreePool (ScsiDevicePath); -Routine Description: + if (DevicePath != NULL) { + FreePool (DevicePath); + } - Discovery SCSI Device + if (ScsiIoDevice != NULL) { + FreePool (ScsiIoDevice); + } -Arguments: + return Status; +} - ScsiIoDevice - The pointer of SCSI_IO_DEV -Returns: +/** + Discovery SCSI Device + + @param ScsiIoDevice The pointer of SCSI_IO_DEV - TRUE - Find SCSI Device and verify it. - FALSE - Unable to find SCSI Device. + @retval TRUE Find SCSI Device and verify it. + @retval FALSE Unable to find SCSI Device. ---*/ +**/ +BOOLEAN +DiscoverScsiDevice ( + IN OUT SCSI_IO_DEV *ScsiIoDevice + ) { EFI_STATUS Status; UINT32 InquiryDataLength; @@ -1072,6 +1180,8 @@ Returns: UINT8 TargetStatus; EFI_SCSI_SENSE_DATA SenseData; EFI_SCSI_INQUIRY_DATA InquiryData; + UINT8 MaxRetry; + UINT8 Index; HostAdapterStatus = 0; TargetStatus = 0; @@ -1079,25 +1189,35 @@ Returns: // 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); - // + SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA); + ZeroMem (&InquiryData, InquiryDataLength); + + MaxRetry = 2; + for (Index = 0; Index < MaxRetry; Index++) { + Status = ScsiInquiryCommand ( + &ScsiIoDevice->ScsiIo, + EFI_TIMER_PERIOD_SECONDS (1), + (VOID *) &SenseData, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus, + (VOID *) &InquiryData, + &InquiryDataLength, + FALSE + ); + if (!EFI_ERROR (Status)) { + break; + } else if ((Status == EFI_BAD_BUFFER_SIZE) || + (Status == EFI_INVALID_PARAMETER) || + (Status == EFI_UNSUPPORTED)) { + return FALSE; + } + } + + if (Index == MaxRetry) { return FALSE; } + // // Retrieved inquiry data successfully // @@ -1112,52 +1232,41 @@ Returns: } } - if (0x1e >= InquiryData.Peripheral_Type >= 0xa) { + 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; + ScsiIoDevice->RemovableDevice = InquiryData.Rmb; if (InquiryData.Version == 0) { ScsiIoDevice->ScsiVersion = 0; } else { // // ANSI-approved version // - ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x03); + ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x07); } return TRUE; } -STATIC +/** + Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet. + + @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET + @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET + +**/ EFI_STATUS EFIAPI ScsiioToPassThruPacket ( IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, - IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket + OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket ) -/*++ - -Routine Description: - - Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to - EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet - -Arguments: - - Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET - CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET - -Returns: - - NONE - ---*/ { // //EFI 1.10 doesn't support Bi-Direction Command. @@ -1165,7 +1274,7 @@ Returns: if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) { return EFI_UNSUPPORTED; } - + ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET)); CommandPacket->Timeout = Packet->Timeout; @@ -1188,30 +1297,19 @@ Returns: } -STATIC +/** + Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet. + + @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET + @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET + +**/ EFI_STATUS EFIAPI PassThruToScsiioPacket ( IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket, - IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet + OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet ) -/*++ - -Routine Description: - - Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to - EFI_SCSI_IO_SCSI_REQUEST_PACKET packet - -Arguments: - - ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET - Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET - -Returns: - - NONE - ---*/ { Packet->Timeout = ScsiPacket->Timeout; Packet->Cdb = ScsiPacket->Cdb; @@ -1229,56 +1327,44 @@ Returns: Packet->OutDataBuffer = ScsiPacket->DataBuffer; Packet->OutTransferLength = ScsiPacket->TransferLength; } - + return EFI_SUCCESS; } +/** + Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0 + SCSI IO Packet. + @param Event The instance of EFI_EVENT. + @param Context The parameter passed in. -STATIC +**/ VOID EFIAPI NotifyFunction ( - EFI_EVENT Event, - VOID *Context + IN EFI_EVENT Event, + IN VOID *Context ) -/*++ - -Routine Description: - - Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0 - SCSI IO Packet. - -Arguments: - - Event - The instance of EFI_EVENT. - Context - The parameter passed in. - -Returns: - - NONE - ---*/ { EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet; EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket; EFI_EVENT CallerEvent; - SCSI_EVENT_DATA *PassData; + SCSI_EVENT_DATA *PassData; PassData = (SCSI_EVENT_DATA*)Context; Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1; - ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)WorkingBuffer; + ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer; // // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet. // PassThruToScsiioPacket(ScsiPacket, Packet); - + // // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet, - // free WorkingBuffer. + // free mWorkingBuffer. // - gBS->FreePool(WorkingBuffer); + gBS->FreePool(mWorkingBuffer); // // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet. @@ -1287,3 +1373,4 @@ Returns: gBS->CloseEvent(Event); gBS->SignalEvent(CallerEvent); } +