git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2338 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			728 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			728 lines
		
	
	
		
			22 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_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
 | |
|   SCSIBusDriverBindingSupported,
 | |
|   SCSIBusDriverBindingStart,
 | |
|   SCSIBusDriverBindingStop,
 | |
|   0xa,
 | |
|   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;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ScsiGetDeviceLocation (
 | |
|   IN  EFI_SCSI_IO_PROTOCOL    *This,
 | |
|   OUT UINT32                  *Target,
 | |
|   OUT UINT64                  *Lun
 | |
|   )
 | |
| /*++
 | |
|   Routine Description:
 | |
|     Retrieves the device location in the SCSI channel.
 | |
|     
 | |
|   Arguments:
 | |
|     This                  - Protocol instance pointer.
 | |
|     Target                - A pointer to the Target ID of a SCSI device 
 | |
|                             on the SCSI channel. 
 | |
|     Lun                   - A pointer to the LUN of the SCSI device on 
 | |
|                             the SCSI channel.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - Retrieves the device location successfully.
 | |
|     EFI_INVALID_PARAMETER - The Target or Lun is NULL.
 | |
| --*/
 | |
| {
 | |
|   SCSI_IO_DEV *ScsiIoDevice;
 | |
| 
 | |
|   if (Target == NULL || Lun == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   ScsiIoDevice  = SCSI_IO_DEV_FROM_THIS (This);
 | |
| 
 | |
|   *Target       = ScsiIoDevice->Pun;
 | |
|   *Lun          = ScsiIoDevice->Lun;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ScsiResetBus (
 | |
|   IN  EFI_SCSI_IO_PROTOCOL     *This
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Resets the SCSI Bus that the SCSI Controller is attached to.
 | |
|     
 | |
|   Arguments:
 | |
|     This                  - Protocol instance pointer.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - The SCSI bus is reset successfully.
 | |
|     EFI_DEVICE_ERROR      - Errors encountered when resetting the SCSI bus.
 | |
|     EFI_UNSUPPORTED       - The bus reset operation is not supported by the
 | |
|                             SCSI Host Controller.
 | |
|     EFI_TIMEOUT           - A timeout occurred while attempting to reset 
 | |
|                             the SCSI bus.
 | |
| --*/
 | |
| {
 | |
|   SCSI_IO_DEV *ScsiIoDevice;
 | |
| 
 | |
|   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
 | |
| 
 | |
|   return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
 | |
| 
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ScsiResetDevice (
 | |
|   IN  EFI_SCSI_IO_PROTOCOL     *This
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Resets the SCSI Controller that the device handle specifies.
 | |
|     
 | |
|   Arguments:
 | |
|     This                  - Protocol instance pointer.
 | |
|     
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - Reset the SCSI controller successfully.
 | |
|     EFI_DEVICE_ERROR      - Errors are encountered when resetting the
 | |
|                             SCSI Controller.
 | |
|     EFI_UNSUPPORTED       - The SCSI bus does not support a device 
 | |
|                             reset operation.
 | |
|     EFI_TIMEOUT           - A timeout occurred while attempting to 
 | |
|                             reset the SCSI Controller.
 | |
| --*/
 | |
| {
 | |
|   SCSI_IO_DEV *ScsiIoDevice;
 | |
| 
 | |
|   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
 | |
| 
 | |
|   return ScsiIoDevice->ScsiPassThru->ResetTarget (
 | |
|                                       ScsiIoDevice->ScsiPassThru,
 | |
|                                       ScsiIoDevice->Pun,
 | |
|                                       ScsiIoDevice->Lun
 | |
|                                       );
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ScsiExecuteSCSICommand (
 | |
|   IN  EFI_SCSI_IO_PROTOCOL                         *This,
 | |
|   IN OUT  EFI_SCSI_IO_SCSI_REQUEST_PACKET          *Packet,
 | |
|   IN EFI_EVENT                                     Event  OPTIONAL
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Sends a SCSI Request Packet to the SCSI Controller for execution.
 | |
|     
 | |
|   Arguments:
 | |
|     This                  - Protocol instance pointer.
 | |
|     Packet                - The SCSI request packet to send to the SCSI 
 | |
|                             Controller specified by the device handle.
 | |
|     Event                 - If the SCSI bus where the SCSI device is attached
 | |
|                             does not support non-blocking I/O, then Event is 
 | |
|                             ignored, and blocking I/O is performed.  
 | |
|                             If Event is NULL, then blocking I/O is performed.
 | |
|                             If Event is not NULL and non-blocking I/O is 
 | |
|                             supported, then non-blocking I/O is performed,
 | |
|                             and Event will be signaled when the SCSI Request
 | |
|                             Packet completes.
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - The SCSI Request Packet was sent by the host 
 | |
|                             successfully, and TransferLength bytes were 
 | |
|                             transferred to/from DataBuffer.See 
 | |
|                             HostAdapterStatus, TargetStatus, 
 | |
|                             SenseDataLength, and SenseData in that order
 | |
|                             for additional status information.
 | |
|     EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, 
 | |
|                             but the entire DataBuffer could not be transferred.
 | |
|                             The actual number of bytes transferred is returned
 | |
|                             in TransferLength. See HostAdapterStatus, 
 | |
|                             TargetStatus, SenseDataLength, and SenseData in 
 | |
|                             that order for additional status information.
 | |
|     EFI_NOT_READY         - The SCSI Request Packet could not be sent because 
 | |
|                             there are too many SCSI Command Packets already 
 | |
|                             queued.The caller may retry again later.
 | |
|     EFI_DEVICE_ERROR      - A device error occurred while attempting to send 
 | |
|                             the SCSI Request Packet. See HostAdapterStatus, 
 | |
|                             TargetStatus, SenseDataLength, and SenseData in 
 | |
|                             that order for additional status information.
 | |
|     EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.  
 | |
|                             The SCSI Request Packet was not sent, so no 
 | |
|                             additional status information is available.
 | |
|     EFI_UNSUPPORTED       - The command described by the SCSI Request Packet
 | |
|                             is not supported by the SCSI initiator(i.e., SCSI 
 | |
|                             Host Controller). The SCSI Request Packet was not
 | |
|                             sent, so no additional status information is 
 | |
|                             available.
 | |
|     EFI_TIMEOUT           - A timeout occurred while waiting for the SCSI 
 | |
|                             Request Packet to execute. See HostAdapterStatus,
 | |
|                             TargetStatus, SenseDataLength, and SenseData in 
 | |
|                             that order for additional status information.
 | |
| --*/
 | |
| {
 | |
|   SCSI_IO_DEV                             *ScsiIoDevice;
 | |
|   EFI_STATUS                              Status;
 | |
| 
 | |
|   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *RequestPacket;
 | |
| 
 | |
|   if (Packet == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   ScsiIoDevice  = SCSI_IO_DEV_FROM_THIS (This);
 | |
| 
 | |
|   RequestPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
 | |
| 
 | |
|   Status = ScsiIoDevice->ScsiPassThru->PassThru (
 | |
|                                         ScsiIoDevice->ScsiPassThru,
 | |
|                                         ScsiIoDevice->Pun,
 | |
|                                         ScsiIoDevice->Lun,
 | |
|                                         RequestPacket,
 | |
|                                         Event
 | |
|                                         );
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| ScsiScanCreateDevice (
 | |
|   EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   EFI_HANDLE                    Controller,
 | |
|   UINT32                        Pun,
 | |
|   UINT64                        Lun,
 | |
|   EFI_SCSI_PASS_THRU_PROTOCOL   *ScsiPassThru,
 | |
|   EFI_DEVICE_PATH_PROTOCOL      *ParentDevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   This              - TODO: add argument description
 | |
|   Controller        - TODO: add argument description
 | |
|   Pun               - TODO: add argument description
 | |
|   Lun               - TODO: add argument description
 | |
|   ScsiPassThru      - TODO: add argument description
 | |
|   ParentDevicePath  - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS - TODO: Add description for return value
 | |
|   EFI_OUT_OF_RESOURCES - TODO: Add description for return value
 | |
|   EFI_SUCCESS - TODO: Add description for return value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   SCSI_IO_DEV               *ScsiIoDevice;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *ScsiDevicePath;
 | |
| 
 | |
|   Status = gBS->AllocatePool (
 | |
|                   EfiBootServicesData,
 | |
|                   sizeof (SCSI_IO_DEV),
 | |
|                   (VOID **) &ScsiIoDevice
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (ScsiIoDevice, sizeof (SCSI_IO_DEV));
 | |
| 
 | |
|   ScsiIoDevice->Signature                 = SCSI_IO_DEV_SIGNATURE;
 | |
|   ScsiIoDevice->ScsiPassThru              = ScsiPassThru;
 | |
|   ScsiIoDevice->Pun                       = Pun;
 | |
|   ScsiIoDevice->Lun                       = Lun;
 | |
| 
 | |
|   ScsiIoDevice->ScsiIo.GetDeviceType      = ScsiGetDeviceType;
 | |
|   ScsiIoDevice->ScsiIo.GetDeviceLocation  = ScsiGetDeviceLocation;
 | |
|   ScsiIoDevice->ScsiIo.ResetBus           = ScsiResetBus;
 | |
|   ScsiIoDevice->ScsiIo.ResetDevice        = ScsiResetDevice;
 | |
|   ScsiIoDevice->ScsiIo.ExecuteSCSICommand = ScsiExecuteSCSICommand;
 | |
| 
 | |
|   if (!DiscoverScsiDevice (ScsiIoDevice)) {
 | |
|     gBS->FreePool (ScsiIoDevice);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Set Device Path
 | |
|   //
 | |
|   Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (
 | |
|                                         ScsiIoDevice->ScsiPassThru,
 | |
|                                         ScsiIoDevice->Pun,
 | |
|                                         ScsiIoDevice->Lun,
 | |
|                                         &ScsiDevicePath
 | |
|                                         );
 | |
|   if (Status == EFI_OUT_OF_RESOURCES) {
 | |
|     gBS->FreePool (ScsiIoDevice);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ScsiIoDevice->DevicePath = AppendDevicePathNode (
 | |
|                               ParentDevicePath,
 | |
|                               ScsiDevicePath
 | |
|                               );
 | |
|   //
 | |
|   // The memory space for ScsiDevicePath is allocated in
 | |
|   // ScsiPassThru->BuildDevicePath() function; It is no longer used
 | |
|   // after EfiAppendDevicePathNode,so free the memory it occupies.
 | |
|   //
 | |
|   gBS->FreePool (ScsiDevicePath);
 | |
| 
 | |
|   if (ScsiIoDevice->DevicePath == NULL) {
 | |
|     gBS->FreePool (ScsiIoDevice);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &ScsiIoDevice->Handle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   ScsiIoDevice->DevicePath,
 | |
|                   &gEfiScsiIoProtocolGuid,
 | |
|                   &ScsiIoDevice->ScsiIo,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     gBS->FreePool (ScsiIoDevice);
 | |
|   } else {
 | |
|     gBS->OpenProtocol (
 | |
|           Controller,
 | |
|           &gEfiScsiPassThruProtocolGuid,
 | |
|           (VOID **) &ScsiPassThru,
 | |
|           This->DriverBindingHandle,
 | |
|           ScsiIoDevice->Handle,
 | |
|           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|           );
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| BOOLEAN
 | |
| DiscoverScsiDevice (
 | |
|   SCSI_IO_DEV   *ScsiIoDevice
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   TODO: Add function description
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   ScsiIoDevice  - TODO: add argument description
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   TODO: add return values
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_SCSI_INQUIRY_DATA InquiryData;
 | |
|   UINT32                InquiryDataLength;
 | |
|   EFI_SCSI_SENSE_DATA   SenseData;
 | |
|   UINT8                 SenseDataLength;
 | |
|   UINT8                 HostAdapterStatus;
 | |
|   UINT8                 TargetStatus;
 | |
| 
 | |
|   HostAdapterStatus = 0;
 | |
|   TargetStatus      = 0;
 | |
|   //
 | |
|   // Using Inquiry command to scan for the device
 | |
|   //
 | |
|   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
 | |
|   SenseDataLength   = sizeof (EFI_SCSI_SENSE_DATA);
 | |
| 
 | |
|   Status = SubmitInquiryCommand (
 | |
|             &ScsiIoDevice->ScsiIo,
 | |
|             EfiScsiStallSeconds (1),
 | |
|             (VOID *) &SenseData,
 | |
|             &SenseDataLength,
 | |
|             &HostAdapterStatus,
 | |
|             &TargetStatus,
 | |
|             (VOID *) &InquiryData,
 | |
|             &InquiryDataLength,
 | |
|             FALSE
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     //    ParseSenseData (&SenseData,SenseDataLength);
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // Retrieved inquiry data successfully
 | |
|   //
 | |
|   if ((InquiryData.Peripheral_Qualifier != 0) &&
 | |
|       (InquiryData.Peripheral_Qualifier != 3)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (InquiryData.Peripheral_Qualifier == 3) {
 | |
|     if (InquiryData.Peripheral_Type != 0x1f) {
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((0x1e >= InquiryData.Peripheral_Type) && (InquiryData.Peripheral_Type >= 0xa)) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // valid device type and peripheral qualifier combination.
 | |
|   //
 | |
|   ScsiIoDevice->ScsiDeviceType  = InquiryData.Peripheral_Type;
 | |
|   ScsiIoDevice->RemovableDevice = InquiryData.RMB;
 | |
|   if (InquiryData.Version == 0) {
 | |
|     ScsiIoDevice->ScsiVersion = 0;
 | |
|   } else {
 | |
|     //
 | |
|     // ANSI-approved version
 | |
|     //
 | |
|     ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x03);
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 |