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