-/*++\r
+/** @file\r
+ SCSI Bus driver that layers on every SCSI Pass Thru and\r
+ Extended SCSI Pass Thru protocol in the system.\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
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+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
-Module Name:\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
- scsibus.c\r
- \r
-Abstract: \r
- \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
+\r
EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {\r
SCSIBusDriverBindingSupported,\r
SCSIBusDriverBindingStart,\r
NULL\r
};\r
\r
+\r
+//\r
+// The ScsiBusProtocol is just used to locate ScsiBusDev\r
+// structure in the SCSIBusDriverBindingStop(). Then we can\r
+// Close all opened protocols and release this structure.\r
+//\r
+EFI_GUID mScsiBusProtocolGuid = EFI_SCSI_BUS_PROTOCOL_GUID;\r
+\r
+VOID *mWorkingBuffer;\r
+\r
+/**\r
+ Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.\r
+\r
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
+ @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiioToPassThruPacket (\r
+ IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
+ OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket\r
+ );\r
+\r
+/**\r
+ Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.\r
+\r
+ @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PassThruToScsiioPacket (\r
+ IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,\r
+ OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet\r
+ );\r
+\r
+/**\r
+ Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0\r
+ SCSI IO Packet.\r
+\r
+ @param Event The instance of EFI_EVENT.\r
+ @param Context The parameter passed in.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+NotifyFunction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\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
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param 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
//\r
// Install driver model protocol(s).\r
//\r
- Status = EfiLibInstallAllDriverProtocols (\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
ImageHandle,\r
SystemTable,\r
&gSCSIBusDriverBinding,\r
ImageHandle,\r
&gScsiBusComponentName,\r
- NULL,\r
- NULL\r
+ &gScsiBusComponentName2\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
-\r
return Status;\r
}\r
\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle.\r
+\r
+ This service is called by the EFI boot service ConnectController(). In order\r
+ to make drivers as small as possible, there are a few calling restrictions for\r
+ this service. ConnectController() must follow these calling restrictions. If\r
+ any other agent wishes to call Supported() it must also follow these calling\r
+ restrictions.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to test\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device\r
+ @retval other This driver does not support this device\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
SCSIBusDriverBindingSupported (\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
+ EFI_STATUS Status;\r
+ EFI_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;\r
+ UINT64 Lun;\r
+ UINT8 *TargetId;\r
+ SCSI_TARGET_ID ScsiTargetId;\r
+\r
+ TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];\r
+ SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\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
+ // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as \r
+ // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly\r
+ // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.\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
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ (VOID **)&ExtPassThru,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ } else if (!EFI_ERROR(Status)) {\r
+ //\r
+ // Check if RemainingDevicePath is NULL or the End of Device Path Node,\r
+ // if yes, return EFI_SUCCESS.\r
+ //\r
+ if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // Close protocol regardless of RemainingDevicePath validation\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ ); \r
+ return EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // If RemainingDevicePath isn't the End of Device Path Node, check its validation\r
+ //\r
+ Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun);\r
+ //\r
+ // Close protocol regardless of RemainingDevicePath validation\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ ); \r
+ if (!EFI_ERROR(Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
}\r
}\r
+\r
//\r
- // check for the existence of SCSI Pass Thru Protocol\r
+ // Come here in 2 condition: \r
+ // 1. ExtPassThru doesn't exist.\r
+ // 2. ExtPassThru exists but RemainingDevicePath is invalid.\r
//\r
Status = gBS->OpenProtocol (\r
Controller,\r
&gEfiScsiPassThruProtocolGuid,\r
- NULL,\r
+ (VOID **)&PassThru,\r
This->DriverBindingHandle,\r
Controller,\r
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
);\r
- if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
- return EFI_UNSUPPORTED;\r
+ \r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
}\r
-\r
- return EFI_SUCCESS;\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Test RemainingDevicePath is valid or not.\r
+ //\r
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
+ Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
+ }\r
+ \r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\r
}\r
\r
+\r
+/**\r
+ Start this driver on ControllerHandle.\r
+\r
+ This service is called by the EFI boot service ConnectController(). In order\r
+ to make drivers as small as possible, there are a few calling restrictions for\r
+ this service. ConnectController() must follow these calling restrictions. If\r
+ any other agent wishes to call Start() it must also follow these calling\r
+ restrictions.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to bind driver to\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCESS This driver is added to ControllerHandle\r
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
+ @retval other This driver does not support this device\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
SCSIBusDriverBindingStart (\r
IN EFI_HANDLE Controller,\r
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
)\r
-/*++\r
- \r
- Routine Description:\r
- \r
- Arguments:\r
+{\r
+ UINT64 Lun;\r
+ UINT8 *TargetId;\r
+ BOOLEAN ScanOtherPuns;\r
+ BOOLEAN FromFirstTarget;\r
+ BOOLEAN ExtScsiSupport;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS DevicePathStatus;\r
+ EFI_STATUS PassThruStatus;\r
+ SCSI_BUS_DEVICE *ScsiBusDev;\r
+ SCSI_TARGET_ID ScsiTargetId;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface;\r
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface;\r
+ EFI_SCSI_BUS_PROTOCOL *BusIdentify;\r
+\r
+ TargetId = NULL;\r
+ ScanOtherPuns = TRUE;\r
+ FromFirstTarget = FALSE;\r
+ ExtScsiSupport = FALSE;\r
+ PassThruStatus = EFI_SUCCESS;\r
\r
- Returns:\r
+ TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];\r
+ SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\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
+ DevicePathStatus = 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 (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) {\r
+ return DevicePathStatus;\r
}\r
\r
//\r
- // Consume SCSI Pass Thru protocol.\r
+ // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as \r
+ // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly\r
+ // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.\r
//\r
Status = gBS->OpenProtocol (\r
Controller,\r
- &gEfiScsiPassThruProtocolGuid,\r
- (VOID **) &ScsiPassThru,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ (VOID **) &ExtScsiInterface,\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
+ // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.\r
+ //\r
+ if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ (VOID **) &ScsiInterface,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ //\r
+ // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.\r
+ //\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ if (!EFI_ERROR(DevicePathStatus)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ } \r
+ return Status;\r
+ } \r
+ } else {\r
+ //\r
+ // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol \r
+ // with BY_DRIVER if it is also present on the handle. The intent is to prevent \r
+ // another SCSI Bus Driver to work on the same host handle.\r
+ //\r
+ ExtScsiSupport = TRUE;\r
+ PassThruStatus = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ (VOID **) &ScsiInterface,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
}\r
+ \r
+ if (Status != EFI_ALREADY_STARTED) {\r
+ //\r
+ // Go through here means either ExtPassThru or PassThru Protocol is successfully opened\r
+ // on this handle for this time. Then construct Host controller private data.\r
+ //\r
+ ScsiBusDev = NULL;\r
+ ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE));\r
+ if (ScsiBusDev == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+ ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE;\r
+ ScsiBusDev->ExtScsiSupport = ExtScsiSupport;\r
+ ScsiBusDev->DevicePath = ParentDevicePath;\r
+ if (ScsiBusDev->ExtScsiSupport) {\r
+ ScsiBusDev->ExtScsiInterface = ExtScsiInterface;\r
+ } else {\r
+ ScsiBusDev->ScsiInterface = ScsiInterface; \r
+ }\r
\r
- if (RemainingDevicePath == NULL) {\r
- StartPun = 0xFFFFFFFF;\r
- StartLun = 0;\r
+ //\r
+ // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be\r
+ // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru\r
+ // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.\r
+ // \r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &mScsiBusProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &ScsiBusDev->BusIdentify\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ErrorExit;\r
+ }\r
} else {\r
- ScsiPassThru->GetTargetLun (ScsiPassThru, RemainingDevicePath, &StartPun, &StartLun);\r
+ //\r
+ // Go through here means Start() is re-invoked again, nothing special is required to do except\r
+ // picking up Host controller private information.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &mScsiBusProtocolGuid,\r
+ (VOID **) &BusIdentify,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);\r
}\r
\r
- for (Pun = StartPun, ScanOtherPuns = TRUE; ScanOtherPuns;) {\r
+ Lun = 0;\r
+ if (RemainingDevicePath == NULL) {\r
+ //\r
+ // If RemainingDevicePath is NULL, \r
+ // must enumerate all SCSI devices anyway\r
+ //\r
+ FromFirstTarget = TRUE;\r
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // If RemainingDevicePath isn't the End of Device Path Node, \r
+ // only scan the specified device by RemainingDevicePath\r
+ //\r
+ if (ScsiBusDev->ExtScsiSupport) {\r
+ Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun); \r
+ } else {\r
+ Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
+ }\r
\r
- if (StartPun == 0xFFFFFFFF) {\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ //\r
+ // If RemainingDevicePath is the End of Device Path Node,\r
+ // skip enumerate any device and return EFI_SUCESSS\r
+ // \r
+ ScanOtherPuns = FALSE;\r
+ }\r
+\r
+ while(ScanOtherPuns) {\r
+ if (FromFirstTarget) {\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 (ScsiBusDev->ExtScsiSupport) {\r
+ Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);\r
+ } else {\r
+ Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
+ }\r
if (EFI_ERROR (Status)) {\r
//\r
// no legal Pun and Lun found any more\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
+ if (ScsiBusDev->ExtScsiSupport) {\r
+ if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {\r
+ continue;\r
+ }\r
+ } else {\r
+ if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {\r
+ continue;\r
+ }\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
+ Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);\r
}\r
+ return EFI_SUCCESS;\r
\r
+ErrorExit:\r
+ \r
+ if (ScsiBusDev != NULL) {\r
+ FreePool (ScsiBusDev);\r
+ }\r
+ \r
+ if (ExtScsiSupport) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ if (!EFI_ERROR (PassThruStatus)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+ } else {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
return Status;\r
}\r
\r
+/**\r
+ Stop this driver on ControllerHandle.\r
+\r
+ This service is called by the EFI boot service DisconnectController().\r
+ In order to make drivers as small as possible, there are a few calling\r
+ restrictions for this service. DisconnectController() must follow these\r
+ calling restrictions. If any other agent wishes to call Stop() it must also\r
+ follow these calling restrictions.\r
+ \r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to stop driver on\r
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
+ children is zero stop the entire bus driver.\r
+ @param ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+ @retval EFI_SUCCESS This driver is removed ControllerHandle\r
+ @retval other This driver was not removed from this device\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
SCSIBusDriverBindingStop (\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
+ VOID *ScsiPassThru;\r
+ EFI_SCSI_BUS_PROTOCOL *Scsidentifier;\r
+ SCSI_BUS_DEVICE *ScsiBusDev;\r
\r
if (NumberOfChildren == 0) {\r
+ //\r
+ // Get the SCSI_BUS_DEVICE\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &mScsiBusProtocolGuid,\r
+ (VOID **) &Scsidentifier,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);\r
+\r
+ //\r
+ // Uninstall SCSI Bus Protocol\r
+ //\r
+ gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &mScsiBusProtocolGuid,\r
+ &ScsiBusDev->BusIdentify\r
+ );\r
+\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
+ if (ScsiBusDev->ExtScsiSupport) {\r
+ //\r
+ // Close ExtPassThru Protocol from this controller handle\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ //\r
+ // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.\r
+ // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle. \r
+ // So Stop() needs to try to close PassThru if present here.\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ } else {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ FreePool (ScsiBusDev);\r
return EFI_SUCCESS;\r
}\r
\r
//\r
// Close the child handle\r
//\r
- Status = gBS->CloseProtocol (\r
- Controller,\r
- &gEfiScsiPassThruProtocolGuid,\r
- This->DriverBindingHandle,\r
- ChildHandleBuffer[Index]\r
- );\r
+ if (ScsiIoDevice->ExtScsiSupport) {\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ } else {\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+ }\r
\r
Status = gBS->UninstallMultipleProtocolInterfaces (\r
ChildHandleBuffer[Index],\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
+ if (ScsiIoDevice->ExtScsiSupport) {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ &ScsiPassThru,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ &ScsiPassThru,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ }\r
} else {\r
- gBS->FreePool (ScsiIoDevice);\r
+ FreePool (ScsiIoDevice);\r
}\r
}\r
\r
return EFI_SUCCESS;\r
}\r
\r
+\r
+/**\r
+ Retrieves the device type information of the SCSI Controller.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param DeviceType A pointer to the device type information retrieved from\r
+ the SCSI Controller. \r
+\r
+ @retval EFI_SUCCESS Retrieves the device type information successfully.\r
+ @retval EFI_INVALID_PARAMETER The DeviceType is NULL.\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
return EFI_SUCCESS;\r
}\r
\r
-STATIC\r
+\r
+/**\r
+ Retrieves the device location in the SCSI channel.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Target A pointer to the Target ID of a SCSI device\r
+ on the SCSI channel.\r
+ @param Lun A pointer to the LUN of the SCSI device on\r
+ the SCSI channel.\r
+\r
+ @retval EFI_SUCCESS Retrieves the device location successfully.\r
+ @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
ScsiGetDeviceLocation (\r
IN EFI_SCSI_IO_PROTOCOL *This,\r
- OUT UINT32 *Target,\r
+ IN OUT UINT8 **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
return EFI_INVALID_PARAMETER;\r
}\r
\r
- ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
+\r
+ CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
\r
- *Target = ScsiIoDevice->Pun;\r
- *Lun = ScsiIoDevice->Lun;\r
+ *Lun = ScsiIoDevice->Lun;\r
\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Resets the SCSI Bus that the SCSI Controller is attached to.\r
+\r
+ @param This Protocol instance pointer.\r
+\r
+ @retval EFI_SUCCESS The SCSI bus is reset successfully.\r
+ @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.\r
+ @retval EFI_UNSUPPORTED The bus reset operation is not supported by the\r
+ SCSI Host Controller.\r
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset \r
+ the SCSI bus.\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
+ if (ScsiIoDevice->ExtScsiSupport){\r
+ return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);\r
+ } else {\r
+ return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);\r
+ }\r
}\r
\r
+\r
+/**\r
+ Resets the SCSI Controller that the device handle specifies.\r
+\r
+ @param This Protocol instance pointer.\r
+\r
+ @retval EFI_SUCCESS Reset the SCSI controller successfully.\r
+ @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.\r
+ @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.\r
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the\r
+ SCSI Controller.\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
+ SCSI_IO_DEV *ScsiIoDevice;\r
+ UINT8 Target[TARGET_MAX_BYTES];\r
\r
ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
+ CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
+\r
\r
- return ScsiIoDevice->ScsiPassThru->ResetTarget (\r
- ScsiIoDevice->ScsiPassThru,\r
- ScsiIoDevice->Pun,\r
- ScsiIoDevice->Lun\r
- );\r
+ if (ScsiIoDevice->ExtScsiSupport) {\r
+ return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (\r
+ ScsiIoDevice->ExtScsiPassThru,\r
+ Target,\r
+ ScsiIoDevice->Lun\r
+ );\r
+ } else {\r
+ return ScsiIoDevice->ScsiPassThru->ResetTarget (\r
+ ScsiIoDevice->ScsiPassThru,\r
+ ScsiIoDevice->Pun.ScsiId.Scsi,\r
+ ScsiIoDevice->Lun\r
+ );\r
+ }\r
}\r
\r
+\r
+/**\r
+ Sends a SCSI Request Packet to the SCSI Controller for execution.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param CommandPacket The SCSI request packet to send to the SCSI \r
+ Controller specified by the device handle.\r
+ @param 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
+\r
+ @retval 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
+ @retval EFI_BAD_BUFFER_SIZE 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
+ @retval 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
+ @retval 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
+ @retval 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
+ @retval 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
+ @retval 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
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
+ 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
+ SCSI_IO_DEV *ScsiIoDevice;\r
+ EFI_STATUS Status;\r
+ UINT8 Target[TARGET_MAX_BYTES];\r
+ EFI_EVENT PacketEvent;\r
+ EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;\r
+ SCSI_EVENT_DATA EventData; \r
+\r
+ PacketEvent = NULL;\r
+ \r
if (Packet == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
+ CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
+\r
+ if (ScsiIoDevice->ExtScsiSupport) {\r
+ ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;\r
+ Status = ScsiIoDevice->ExtScsiPassThru->PassThru (\r
+ ScsiIoDevice->ExtScsiPassThru,\r
+ Target,\r
+ ScsiIoDevice->Lun,\r
+ ExtRequestPacket,\r
+ Event\r
+ );\r
+ } else {\r
\r
- RequestPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;\r
+ mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_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
+ if (mWorkingBuffer == NULL) {\r
+ return EFI_DEVICE_ERROR;\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
+ // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.\r
+ //\r
+ Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(mWorkingBuffer);\r
+ return Status;\r
+ }\r
\r
-Routine Description:\r
+ if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {\r
+ EventData.Data1 = (VOID*)Packet;\r
+ EventData.Data2 = Event;\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ NotifyFunction,\r
+ &EventData,\r
+ &PacketEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(mWorkingBuffer);\r
+ return Status;\r
+ }\r
\r
- TODO: Add function description\r
+ Status = ScsiIoDevice->ScsiPassThru->PassThru (\r
+ ScsiIoDevice->ScsiPassThru,\r
+ ScsiIoDevice->Pun.ScsiId.Scsi,\r
+ ScsiIoDevice->Lun,\r
+ mWorkingBuffer,\r
+ PacketEvent\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(mWorkingBuffer);\r
+ gBS->CloseEvent(PacketEvent);\r
+ return Status;\r
+ }\r
\r
-Arguments:\r
+ } else {\r
+ //\r
+ // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert\r
+ // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.\r
+ //\r
+ Status = ScsiIoDevice->ScsiPassThru->PassThru (\r
+ ScsiIoDevice->ScsiPassThru,\r
+ ScsiIoDevice->Pun.ScsiId.Scsi,\r
+ ScsiIoDevice->Lun,\r
+ mWorkingBuffer,\r
+ Event\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(mWorkingBuffer);\r
+ return Status;\r
+ }\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
+ PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet);\r
+ //\r
+ // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,\r
+ // free mWorkingBuffer.\r
+ //\r
+ FreePool(mWorkingBuffer);\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.\r
\r
-Returns:\r
+ @param This Protocol instance pointer\r
+ @param Controller Controller handle\r
+ @param TargetId Tartget to be scanned\r
+ @param Lun The Lun of the SCSI device on the SCSI channel.\r
+ @param ScsiBusDev The pointer of SCSI_BUS_DEVICE\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
+ @retval EFI_SUCCESS Successfully to discover the device and attach\r
+ ScsiIoProtocol to it.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to discover the device.\r
\r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiScanCreateDevice (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN SCSI_TARGET_ID *TargetId,\r
+ IN UINT64 Lun,\r
+ IN OUT SCSI_BUS_DEVICE *ScsiBusDev\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
+ ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));\r
+ if (ScsiIoDevice == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\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
+ CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);\r
ScsiIoDevice->Lun = Lun;\r
\r
+ if (ScsiBusDev->ExtScsiSupport) {\r
+ ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;\r
+ ScsiIoDevice->ExtScsiSupport = TRUE;\r
+ ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;\r
+\r
+ } else {\r
+ ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface;\r
+ ScsiIoDevice->ExtScsiSupport = FALSE;\r
+ ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;\r
+ }\r
+\r
ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;\r
- // ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;\r
+ ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;\r
ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;\r
ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;\r
ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;\r
\r
+\r
if (!DiscoverScsiDevice (ScsiIoDevice)) {\r
- gBS->FreePool (ScsiIoDevice);\r
- return EFI_SUCCESS;\r
+ FreePool (ScsiIoDevice);\r
+ return EFI_OUT_OF_RESOURCES;\r
}\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
+ ScsiDevicePath = NULL;\r
+ if (ScsiIoDevice->ExtScsiSupport){\r
+ Status = ScsiIoDevice->ExtScsiPassThru->BuildDevicePath (\r
+ ScsiIoDevice->ExtScsiPassThru,\r
+ &ScsiIoDevice->Pun.ScsiId.ExtScsi[0],\r
+ ScsiIoDevice->Lun,\r
+ &ScsiDevicePath\r
+ );\r
+ } else {\r
+ Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (\r
+ ScsiIoDevice->ScsiPassThru,\r
+ ScsiIoDevice->Pun.ScsiId.Scsi,\r
+ ScsiIoDevice->Lun,\r
+ &ScsiDevicePath\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool (ScsiIoDevice);\r
return Status;\r
}\r
\r
ScsiIoDevice->DevicePath = AppendDevicePathNode (\r
- ParentDevicePath,\r
+ ScsiBusDev->DevicePath,\r
ScsiDevicePath\r
);\r
//\r
// ScsiPassThru->BuildDevicePath() function; It is no longer used\r
// after EfiAppendDevicePathNode,so free the memory it occupies.\r
//\r
- gBS->FreePool (ScsiDevicePath);\r
+ FreePool (ScsiDevicePath);\r
\r
if (ScsiIoDevice->DevicePath == NULL) {\r
- gBS->FreePool (ScsiIoDevice);\r
+ FreePool (ScsiIoDevice);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
NULL\r
);\r
if (EFI_ERROR (Status)) {\r
- gBS->FreePool (ScsiIoDevice);\r
+ FreePool (ScsiIoDevice->DevicePath);\r
+ FreePool (ScsiIoDevice);\r
+ return EFI_OUT_OF_RESOURCES;\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
+ if (ScsiBusDev->ExtScsiSupport) {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ (VOID **) &(ScsiBusDev->ExtScsiInterface),\r
+ This->DriverBindingHandle,\r
+ ScsiIoDevice->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiScsiPassThruProtocolGuid,\r
+ (VOID **) &(ScsiBusDev->ScsiInterface),\r
+ This->DriverBindingHandle,\r
+ ScsiIoDevice->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\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
+ Discovery SCSI Device\r
\r
-Returns:\r
+ @param ScsiIoDevice The pointer of SCSI_IO_DEV\r
\r
- TODO: add return values\r
+ @retval TRUE Find SCSI Device and verify it.\r
+ @retval FALSE Unable to find SCSI Device.\r
\r
---*/\r
+**/\r
+BOOLEAN\r
+DiscoverScsiDevice (\r
+ IN OUT SCSI_IO_DEV *ScsiIoDevice\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
+ EFI_SCSI_SENSE_DATA SenseData;\r
+ EFI_SCSI_INQUIRY_DATA InquiryData;\r
\r
HostAdapterStatus = 0;\r
TargetStatus = 0;\r
InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
\r
- Status = SubmitInquiryCommand (\r
+ Status = ScsiInquiryCommand (\r
&ScsiIoDevice->ScsiIo,\r
- EfiScsiStallSeconds (1),\r
+ EFI_TIMER_PERIOD_SECONDS (1),\r
(VOID *) &SenseData,\r
&SenseDataLength,\r
&HostAdapterStatus,\r
&InquiryDataLength,\r
FALSE\r
);\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // ParseSenseData (&SenseData,SenseDataLength);\r
- //\r
+ if (EFI_ERROR (Status) && Status != EFI_BAD_BUFFER_SIZE) {\r
return FALSE;\r
}\r
//\r
}\r
}\r
\r
- if ((0x1e >= InquiryData.Peripheral_Type) && (InquiryData.Peripheral_Type >= 0xa)) {\r
+ if (0x1e >= InquiryData.Peripheral_Type && InquiryData.Peripheral_Type >= 0xa) {\r
return FALSE;\r
}\r
- \r
+\r
//\r
// valid device type and peripheral qualifier combination.\r
//\r
ScsiIoDevice->ScsiDeviceType = InquiryData.Peripheral_Type;\r
- ScsiIoDevice->RemovableDevice = InquiryData.RMB;\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
+ ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x07);\r
}\r
\r
return TRUE;\r
}\r
+\r
+\r
+/**\r
+ Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.\r
+\r
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
+ @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiioToPassThruPacket (\r
+ IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
+ OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket\r
+ )\r
+{\r
+ //\r
+ //EFI 1.10 doesn't support Bi-Direction Command.\r
+ //\r
+ if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
+\r
+ CommandPacket->Timeout = Packet->Timeout;\r
+ CommandPacket->Cdb = Packet->Cdb;\r
+ CommandPacket->CdbLength = Packet->CdbLength;\r
+ CommandPacket->DataDirection = Packet->DataDirection;\r
+ CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;\r
+ CommandPacket->TargetStatus = Packet->TargetStatus;\r
+ CommandPacket->SenseData = Packet->SenseData;\r
+ CommandPacket->SenseDataLength = Packet->SenseDataLength;\r
+\r
+ if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {\r
+ CommandPacket->DataBuffer = Packet->InDataBuffer;\r
+ CommandPacket->TransferLength = Packet->InTransferLength;\r
+ } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {\r
+ CommandPacket->DataBuffer = Packet->OutDataBuffer;\r
+ CommandPacket->TransferLength = Packet->OutTransferLength;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.\r
+\r
+ @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PassThruToScsiioPacket (\r
+ IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,\r
+ OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet\r
+ )\r
+{\r
+ Packet->Timeout = ScsiPacket->Timeout;\r
+ Packet->Cdb = ScsiPacket->Cdb;\r
+ Packet->CdbLength = ScsiPacket->CdbLength;\r
+ Packet->DataDirection = ScsiPacket->DataDirection;\r
+ Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;\r
+ Packet->TargetStatus = ScsiPacket->TargetStatus;\r
+ Packet->SenseData = ScsiPacket->SenseData;\r
+ Packet->SenseDataLength = ScsiPacket->SenseDataLength;\r
+\r
+ if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {\r
+ Packet->InDataBuffer = ScsiPacket->DataBuffer;\r
+ Packet->InTransferLength = ScsiPacket->TransferLength;\r
+ } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {\r
+ Packet->OutDataBuffer = ScsiPacket->DataBuffer;\r
+ Packet->OutTransferLength = ScsiPacket->TransferLength;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0\r
+ SCSI IO Packet.\r
+\r
+ @param Event The instance of EFI_EVENT.\r
+ @param Context The parameter passed in.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+NotifyFunction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;\r
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;\r
+ EFI_EVENT CallerEvent;\r
+ SCSI_EVENT_DATA *PassData;\r
+\r
+ PassData = (SCSI_EVENT_DATA*)Context;\r
+ Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;\r
+ ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;\r
+\r
+ //\r
+ // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.\r
+ //\r
+ PassThruToScsiioPacket(ScsiPacket, Packet);\r
+\r
+ //\r
+ // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,\r
+ // free mWorkingBuffer.\r
+ //\r
+ gBS->FreePool(mWorkingBuffer);\r
+\r
+ //\r
+ // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.\r
+ //\r
+ CallerEvent = PassData->Data2;\r
+ gBS->CloseEvent(Event);\r
+ gBS->SignalEvent(CallerEvent);\r
+}\r
+\r