This causes the device to forget about the reply frame. We allocated the reply frame in EfiBootServicesData type memory, and code executing after ExitBootServices() is permitted to overwrite it. Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2390 Signed-off-by: Nikita Leshenko <nikita.leshchenko@oracle.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Message-Id: <20200504210607.144434-13-nikita.leshchenko@oracle.com>
		
			
				
	
	
		
			1212 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1212 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
|   This driver produces Extended SCSI Pass Thru Protocol instances for
 | |
|   LSI Fusion MPT SCSI devices.
 | |
| 
 | |
|   Copyright (C) 2020, Oracle and/or its affiliates.
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <IndustryStandard/FusionMptScsi.h>
 | |
| #include <IndustryStandard/Pci.h>
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/PcdLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/UefiLib.h>
 | |
| #include <Protocol/PciIo.h>
 | |
| #include <Protocol/PciRootBridgeIo.h>
 | |
| #include <Protocol/ScsiPassThruExt.h>
 | |
| #include <Uefi/UefiSpec.h>
 | |
| 
 | |
| //
 | |
| // Higher versions will be used before lower, 0x10-0xffffffef is the version
 | |
| // range for IVH (Indie Hardware Vendors)
 | |
| //
 | |
| #define MPT_SCSI_BINDING_VERSION 0x10
 | |
| 
 | |
| //
 | |
| // Runtime Structures
 | |
| //
 | |
| 
 | |
| typedef struct {
 | |
|   MPT_SCSI_REQUEST_ALIGNED        IoRequest;
 | |
|   MPT_SCSI_IO_REPLY_ALIGNED       IoReply;
 | |
|   //
 | |
|   // As EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.SenseDataLength is defined
 | |
|   // as UINT8, defining here SenseData size to MAX_UINT8 will guarantee it
 | |
|   // cannot overflow when passed to device.
 | |
|   //
 | |
|   UINT8                           Sense[MAX_UINT8];
 | |
|   //
 | |
|   // This size of the data is arbitrarily chosen.
 | |
|   // It seems to be sufficient for all I/O requests sent through
 | |
|   // EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() for common boot scenarios.
 | |
|   //
 | |
|   UINT8                           Data[0x2000];
 | |
| } MPT_SCSI_DMA_BUFFER;
 | |
| 
 | |
| #define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
 | |
| typedef struct {
 | |
|   UINT32                          Signature;
 | |
|   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
 | |
|   EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
 | |
|   UINT8                           MaxTarget;
 | |
|   UINT32                          StallPerPollUsec;
 | |
|   EFI_PCI_IO_PROTOCOL             *PciIo;
 | |
|   UINT64                          OriginalPciAttributes;
 | |
|   EFI_EVENT                       ExitBoot;
 | |
|   MPT_SCSI_DMA_BUFFER             *Dma;
 | |
|   EFI_PHYSICAL_ADDRESS            DmaPhysical;
 | |
|   VOID                            *DmaMapping;
 | |
|   BOOLEAN                         IoReplyEnqueued;
 | |
| } MPT_SCSI_DEV;
 | |
| 
 | |
| #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
 | |
|   CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
 | |
| 
 | |
| #define MPT_SCSI_DMA_ADDR(Dev, MemberName) \
 | |
|   (Dev->DmaPhysical + OFFSET_OF (MPT_SCSI_DMA_BUFFER, MemberName))
 | |
| 
 | |
| #define MPT_SCSI_DMA_ADDR_HIGH(Dev, MemberName) \
 | |
|   ((UINT32)RShiftU64 (MPT_SCSI_DMA_ADDR (Dev, MemberName), 32))
 | |
| 
 | |
| #define MPT_SCSI_DMA_ADDR_LOW(Dev, MemberName) \
 | |
|   ((UINT32)MPT_SCSI_DMA_ADDR (Dev, MemberName))
 | |
| 
 | |
| //
 | |
| // Hardware functions
 | |
| //
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| Out32 (
 | |
|   IN MPT_SCSI_DEV       *Dev,
 | |
|   IN UINT32             Addr,
 | |
|   IN UINT32             Data
 | |
|   )
 | |
| {
 | |
|   return Dev->PciIo->Io.Write (
 | |
|                           Dev->PciIo,
 | |
|                           EfiPciIoWidthUint32,
 | |
|                           PCI_BAR_IDX0,
 | |
|                           Addr,
 | |
|                           1,
 | |
|                           &Data
 | |
|                           );
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| In32 (
 | |
|   IN  MPT_SCSI_DEV       *Dev,
 | |
|   IN  UINT32             Addr,
 | |
|   OUT UINT32             *Data
 | |
|   )
 | |
| {
 | |
|   return Dev->PciIo->Io.Read (
 | |
|                           Dev->PciIo,
 | |
|                           EfiPciIoWidthUint32,
 | |
|                           PCI_BAR_IDX0,
 | |
|                           Addr,
 | |
|                           1,
 | |
|                           Data
 | |
|                           );
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MptDoorbell (
 | |
|   IN MPT_SCSI_DEV       *Dev,
 | |
|   IN UINT8              DoorbellFunc,
 | |
|   IN UINT8              DoorbellArg
 | |
|   )
 | |
| {
 | |
|   return Out32 (
 | |
|            Dev,
 | |
|            MPT_REG_DOORBELL,
 | |
|            (((UINT32)DoorbellFunc) << 24) | (DoorbellArg << 16)
 | |
|            );
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MptScsiReset (
 | |
|   IN MPT_SCSI_DEV       *Dev
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
| 
 | |
|   //
 | |
|   // Reset hardware
 | |
|   //
 | |
|   Status = MptDoorbell (Dev, MPT_DOORBELL_RESET, 0);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Mask interrupts
 | |
|   //
 | |
|   Status = Out32 (Dev, MPT_REG_IMASK, MPT_IMASK_DOORBELL | MPT_IMASK_REPLY);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Clear interrupt status
 | |
|   //
 | |
|   Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MptScsiInit (
 | |
|   IN MPT_SCSI_DEV       *Dev
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   union {
 | |
|     MPT_IO_CONTROLLER_INIT_REQUEST Data;
 | |
|     UINT32                         Uint32;
 | |
|   } AlignedReq;
 | |
|   MPT_IO_CONTROLLER_INIT_REQUEST   *Req;
 | |
|   MPT_IO_CONTROLLER_INIT_REPLY     Reply;
 | |
|   UINT8                            *ReplyBytes;
 | |
|   UINT32                           ReplyWord;
 | |
| 
 | |
|   Req = &AlignedReq.Data;
 | |
| 
 | |
|   Status = MptScsiReset (Dev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (Req, sizeof (*Req));
 | |
|   ZeroMem (&Reply, sizeof (Reply));
 | |
|   Req->WhoInit = MPT_IOC_WHOINIT_ROM_BIOS;
 | |
|   Req->Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT;
 | |
|   STATIC_ASSERT (
 | |
|     FixedPcdGet8 (PcdMptScsiMaxTargetLimit) < 255,
 | |
|     "Req supports 255 targets only (max target is 254)"
 | |
|     );
 | |
|   Req->MaxDevices = Dev->MaxTarget + 1;
 | |
|   Req->MaxBuses = 1;
 | |
|   Req->ReplyFrameSize = sizeof Dev->Dma->IoReply.Data;
 | |
|   Req->HostMfaHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, IoRequest);
 | |
|   Req->SenseBufferHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, Sense);
 | |
| 
 | |
|   //
 | |
|   // Send controller init through doorbell
 | |
|   //
 | |
|   STATIC_ASSERT (
 | |
|     sizeof (*Req) % sizeof (UINT32) == 0,
 | |
|     "Req must be multiple of UINT32"
 | |
|     );
 | |
|   STATIC_ASSERT (
 | |
|     sizeof (*Req) / sizeof (UINT32) <= MAX_UINT8,
 | |
|     "Req must fit in MAX_UINT8 Dwords"
 | |
|     );
 | |
|   Status = MptDoorbell (
 | |
|              Dev,
 | |
|              MPT_DOORBELL_HANDSHAKE,
 | |
|              (UINT8)(sizeof (*Req) / sizeof (UINT32))
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   Status = Dev->PciIo->Io.Write (
 | |
|                             Dev->PciIo,
 | |
|                             EfiPciIoWidthFifoUint32,
 | |
|                             PCI_BAR_IDX0,
 | |
|                             MPT_REG_DOORBELL,
 | |
|                             sizeof (*Req) / sizeof (UINT32),
 | |
|                             Req
 | |
|                             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Read reply through doorbell
 | |
|   // Each 32bit (Dword) read produces 16bit (Word) of data
 | |
|   //
 | |
|   // The reply is read back to complete the doorbell function but it
 | |
|   // isn't useful because it doesn't contain relevant data or status
 | |
|   // codes.
 | |
|   //
 | |
|   STATIC_ASSERT (
 | |
|     sizeof (Reply) % sizeof (UINT16) == 0,
 | |
|     "Reply must be multiple of UINT16"
 | |
|     );
 | |
|   ReplyBytes = (UINT8 *)&Reply;
 | |
|   while (ReplyBytes != (UINT8 *)(&Reply + 1)) {
 | |
|     Status = In32 (Dev, MPT_REG_DOORBELL, &ReplyWord);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     CopyMem (ReplyBytes, &ReplyWord, sizeof (UINT16));
 | |
|     ReplyBytes += sizeof (UINT16);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Clear interrupts generated by doorbell reply
 | |
|   //
 | |
|   Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| ReportHostAdapterError (
 | |
|   OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
 | |
|   )
 | |
| {
 | |
|   DEBUG ((DEBUG_ERROR, "%a: fatal error in scsi request\n", __FUNCTION__));
 | |
|   Packet->InTransferLength  = 0;
 | |
|   Packet->OutTransferLength = 0;
 | |
|   Packet->SenseDataLength   = 0;
 | |
|   Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
 | |
|   Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
 | |
|   return EFI_DEVICE_ERROR;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| ReportHostAdapterOverrunError (
 | |
|   OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
 | |
|   )
 | |
| {
 | |
|   Packet->SenseDataLength = 0;
 | |
|   Packet->HostAdapterStatus =
 | |
|             EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
 | |
|   Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
 | |
|   return EFI_BAD_BUFFER_SIZE;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MptScsiPopulateRequest (
 | |
|   IN MPT_SCSI_DEV                                   *Dev,
 | |
|   IN UINT8                                          Target,
 | |
|   IN UINT64                                         Lun,
 | |
|   IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
 | |
|   )
 | |
| {
 | |
|   MPT_SCSI_REQUEST_WITH_SG *Request;
 | |
| 
 | |
|   Request = &Dev->Dma->IoRequest.Data;
 | |
| 
 | |
|   if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL ||
 | |
|       (Packet->InTransferLength > 0 && Packet->OutTransferLength > 0) ||
 | |
|       Packet->CdbLength > sizeof (Request->Header.Cdb)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (Target > Dev->MaxTarget || Lun > 0 ||
 | |
|       Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL ||
 | |
|       //
 | |
|       // Trying to receive, but destination pointer is NULL, or contradicting
 | |
|       // transfer direction
 | |
|       //
 | |
|       (Packet->InTransferLength > 0 &&
 | |
|        (Packet->InDataBuffer == NULL ||
 | |
|         Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE
 | |
|          )
 | |
|         ) ||
 | |
| 
 | |
|       //
 | |
|       // Trying to send, but source pointer is NULL, or contradicting transfer
 | |
|       // direction
 | |
|       //
 | |
|       (Packet->OutTransferLength > 0 &&
 | |
|        (Packet->OutDataBuffer == NULL ||
 | |
|         Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ
 | |
|          )
 | |
|         )
 | |
|     ) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (Packet->InTransferLength > sizeof (Dev->Dma->Data)) {
 | |
|     Packet->InTransferLength = sizeof (Dev->Dma->Data);
 | |
|     return ReportHostAdapterOverrunError (Packet);
 | |
|   }
 | |
|   if (Packet->OutTransferLength > sizeof (Dev->Dma->Data)) {
 | |
|     Packet->OutTransferLength = sizeof (Dev->Dma->Data);
 | |
|     return ReportHostAdapterOverrunError (Packet);
 | |
|   }
 | |
| 
 | |
|   ZeroMem (Request, sizeof (*Request));
 | |
|   Request->Header.TargetId = Target;
 | |
|   //
 | |
|   // Only LUN 0 is currently supported, hence the cast is safe
 | |
|   //
 | |
|   Request->Header.Lun[1] = (UINT8)Lun;
 | |
|   Request->Header.Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST;
 | |
|   Request->Header.MessageContext = 1; // We handle one request at a time
 | |
| 
 | |
|   Request->Header.CdbLength = Packet->CdbLength;
 | |
|   CopyMem (Request->Header.Cdb, Packet->Cdb, Packet->CdbLength);
 | |
| 
 | |
|   //
 | |
|   // SenseDataLength is UINT8, Sense[] is MAX_UINT8, so we can't overflow
 | |
|   //
 | |
|   ZeroMem (Dev->Dma->Sense, Packet->SenseDataLength);
 | |
|   Request->Header.SenseBufferLength = Packet->SenseDataLength;
 | |
|   Request->Header.SenseBufferLowAddress = MPT_SCSI_DMA_ADDR_LOW (Dev, Sense);
 | |
| 
 | |
|   Request->Sg.EndOfList = 1;
 | |
|   Request->Sg.EndOfBuffer = 1;
 | |
|   Request->Sg.LastElement = 1;
 | |
|   Request->Sg.ElementType = MPT_SG_ENTRY_TYPE_SIMPLE;
 | |
|   Request->Sg.Is64BitAddress = 1;
 | |
|   Request->Sg.DataBufferAddress = MPT_SCSI_DMA_ADDR (Dev, Data);
 | |
| 
 | |
|   //
 | |
|   // "MPT_SG_ENTRY_SIMPLE.Length" is a 24-bit quantity.
 | |
|   //
 | |
|   STATIC_ASSERT (
 | |
|     sizeof (Dev->Dma->Data) < SIZE_16MB,
 | |
|     "MPT_SCSI_DMA_BUFFER.Data must be smaller than 16MB"
 | |
|     );
 | |
| 
 | |
|   if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
 | |
|     Request->Header.DataLength = Packet->InTransferLength;
 | |
|     Request->Sg.Length = Packet->InTransferLength;
 | |
|     Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ;
 | |
|   } else {
 | |
|     Request->Header.DataLength = Packet->OutTransferLength;
 | |
|     Request->Sg.Length = Packet->OutTransferLength;
 | |
|     Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE;
 | |
| 
 | |
|     CopyMem (Dev->Dma->Data, Packet->OutDataBuffer, Packet->OutTransferLength);
 | |
|     Request->Sg.BufferContainsData = 1;
 | |
|   }
 | |
| 
 | |
|   if (Request->Header.DataLength == 0) {
 | |
|     Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MptScsiSendRequest (
 | |
|   IN MPT_SCSI_DEV                                   *Dev,
 | |
|   IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
| 
 | |
|   if (!Dev->IoReplyEnqueued) {
 | |
|     //
 | |
|     // Put one free reply frame on the reply queue, the hardware may use it to
 | |
|     // report an error to us.
 | |
|     //
 | |
|     Status = Out32 (Dev, MPT_REG_REP_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoReply));
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
|     Dev->IoReplyEnqueued = TRUE;
 | |
|   }
 | |
| 
 | |
|   Status = Out32 (Dev, MPT_REG_REQ_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoRequest));
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MptScsiGetReply (
 | |
|   IN MPT_SCSI_DEV                                   *Dev,
 | |
|   OUT UINT32                                        *Reply
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINT32     Istatus;
 | |
|   UINT32     EmptyReply;
 | |
| 
 | |
|   //
 | |
|   // Timeouts are not supported for
 | |
|   // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() in this implementation.
 | |
|   //
 | |
|   for (;;) {
 | |
|     Status = In32 (Dev, MPT_REG_ISTATUS, &Istatus);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Interrupt raised
 | |
|     //
 | |
|     if (Istatus & MPT_IMASK_REPLY) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     gBS->Stall (Dev->StallPerPollUsec);
 | |
|   }
 | |
| 
 | |
|   Status = In32 (Dev, MPT_REG_REP_Q, Reply);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // The driver is supposed to fetch replies until 0xffffffff is returned, which
 | |
|   // will reset the interrupt status. We put only one request, so we expect the
 | |
|   // next read reply to be the last.
 | |
|   //
 | |
|   Status = In32 (Dev, MPT_REG_REP_Q, &EmptyReply);
 | |
|   if (EFI_ERROR (Status) || EmptyReply != MAX_UINT32) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MptScsiHandleReply (
 | |
|   IN MPT_SCSI_DEV                                   *Dev,
 | |
|   IN UINT32                                         Reply,
 | |
|   OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
 | |
|   )
 | |
| {
 | |
|   if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
 | |
|     CopyMem (Packet->InDataBuffer, Dev->Dma->Data, Packet->InTransferLength);
 | |
|   }
 | |
| 
 | |
|   if (Reply == Dev->Dma->IoRequest.Data.Header.MessageContext) {
 | |
|     //
 | |
|     // This is a turbo reply, everything is good
 | |
|     //
 | |
|     Packet->SenseDataLength = 0;
 | |
|     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
 | |
|     Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
 | |
| 
 | |
|   } else if ((Reply & BIT31) != 0) {
 | |
|     DEBUG ((DEBUG_INFO, "%a: Full reply returned\n", __FUNCTION__));
 | |
|     //
 | |
|     // When reply MSB is set, we got a full reply. Since we submitted only one
 | |
|     // reply frame, we know it's IoReply.
 | |
|     //
 | |
|     Dev->IoReplyEnqueued = FALSE;
 | |
| 
 | |
|     Packet->TargetStatus = Dev->Dma->IoReply.Data.ScsiStatus;
 | |
|     //
 | |
|     // Make sure device only lowers SenseDataLength before copying sense
 | |
|     //
 | |
|     ASSERT (Dev->Dma->IoReply.Data.SenseCount <= Packet->SenseDataLength);
 | |
|     Packet->SenseDataLength =
 | |
|       (UINT8)MIN (Dev->Dma->IoReply.Data.SenseCount, Packet->SenseDataLength);
 | |
|     CopyMem (Packet->SenseData, Dev->Dma->Sense, Packet->SenseDataLength);
 | |
| 
 | |
|     if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
 | |
|       Packet->InTransferLength = Dev->Dma->IoReply.Data.TransferCount;
 | |
|     } else {
 | |
|       Packet->OutTransferLength = Dev->Dma->IoReply.Data.TransferCount;
 | |
|     }
 | |
| 
 | |
|     switch (Dev->Dma->IoReply.Data.IocStatus) {
 | |
|     case MPT_SCSI_IOCSTATUS_SUCCESS:
 | |
|       Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
 | |
|       break;
 | |
|     case MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE:
 | |
|       Packet->HostAdapterStatus =
 | |
|         EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
 | |
|       return EFI_TIMEOUT;
 | |
|     case MPT_SCSI_IOCSTATUS_DATA_UNDERRUN:
 | |
|     case MPT_SCSI_IOCSTATUS_DATA_OVERRUN:
 | |
|       Packet->HostAdapterStatus =
 | |
|         EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
 | |
|       break;
 | |
|     default:
 | |
|       Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|   } else {
 | |
|     DEBUG ((DEBUG_ERROR, "%a: unexpected reply (%x)\n", __FUNCTION__, Reply));
 | |
|     return ReportHostAdapterError (Packet);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // Ext SCSI Pass Thru
 | |
| //
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiPassThru (
 | |
|   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
 | |
|   IN UINT8                                          *Target,
 | |
|   IN UINT64                                         Lun,
 | |
|   IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
 | |
|   IN EFI_EVENT                                      Event     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS   Status;
 | |
|   MPT_SCSI_DEV *Dev;
 | |
|   UINT32       Reply;
 | |
| 
 | |
|   Dev = MPT_SCSI_FROM_PASS_THRU (This);
 | |
|   //
 | |
|   // We only use first byte of target identifer
 | |
|   //
 | |
|   Status = MptScsiPopulateRequest (Dev, *Target, Lun, Packet);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // MptScsiPopulateRequest modified packet according to the error
 | |
|     //
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = MptScsiSendRequest (Dev, Packet);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return ReportHostAdapterError (Packet);
 | |
|   }
 | |
| 
 | |
|   Status = MptScsiGetReply (Dev, &Reply);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return ReportHostAdapterError (Packet);
 | |
|   }
 | |
| 
 | |
|   return MptScsiHandleReply (Dev, Reply, Packet);
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| BOOLEAN
 | |
| IsTargetInitialized (
 | |
|   IN UINT8                                          *Target
 | |
|   )
 | |
| {
 | |
|   UINTN Idx;
 | |
| 
 | |
|   for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
 | |
|     if (Target[Idx] != 0xFF) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiGetNextTargetLun (
 | |
|   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
 | |
|   IN OUT UINT8                                      **Target,
 | |
|   IN OUT UINT64                                     *Lun
 | |
|   )
 | |
| {
 | |
|   MPT_SCSI_DEV *Dev;
 | |
| 
 | |
|   Dev = MPT_SCSI_FROM_PASS_THRU (This);
 | |
|   //
 | |
|   // Currently support only LUN 0, so hardcode it
 | |
|   //
 | |
|   if (!IsTargetInitialized (*Target)) {
 | |
|     ZeroMem (*Target, TARGET_MAX_BYTES);
 | |
|     *Lun = 0;
 | |
|   } else if (**Target > Dev->MaxTarget || *Lun > 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   } else if (**Target < Dev->MaxTarget) {
 | |
|     //
 | |
|     // This device interface support 256 targets only, so it's enough to
 | |
|     // increment the LSB of Target, as it will never overflow.
 | |
|     //
 | |
|     **Target += 1;
 | |
|   } else {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiGetNextTarget (
 | |
|   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL               *This,
 | |
|   IN OUT UINT8                                     **Target
 | |
|   )
 | |
| {
 | |
|   MPT_SCSI_DEV *Dev;
 | |
| 
 | |
|   Dev = MPT_SCSI_FROM_PASS_THRU (This);
 | |
|   if (!IsTargetInitialized (*Target)) {
 | |
|     ZeroMem (*Target, TARGET_MAX_BYTES);
 | |
|   } else if (**Target > Dev->MaxTarget) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   } else if (**Target < Dev->MaxTarget) {
 | |
|     //
 | |
|     // This device interface support 256 targets only, so it's enough to
 | |
|     // increment the LSB of Target, as it will never overflow.
 | |
|     //
 | |
|     **Target += 1;
 | |
|   } else {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiBuildDevicePath (
 | |
|   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL               *This,
 | |
|   IN UINT8                                         *Target,
 | |
|   IN UINT64                                        Lun,
 | |
|   IN OUT EFI_DEVICE_PATH_PROTOCOL                  **DevicePath
 | |
|   )
 | |
| {
 | |
|   MPT_SCSI_DEV     *Dev;
 | |
|   SCSI_DEVICE_PATH *ScsiDevicePath;
 | |
| 
 | |
|   if (DevicePath == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // This device support 256 targets only, so it's enough to dereference
 | |
|   // the LSB of Target.
 | |
|   //
 | |
|   Dev = MPT_SCSI_FROM_PASS_THRU (This);
 | |
|   if (*Target > Dev->MaxTarget || Lun > 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   ScsiDevicePath = AllocateZeroPool (sizeof (*ScsiDevicePath));
 | |
|   if (ScsiDevicePath == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   ScsiDevicePath->Header.Type      = MESSAGING_DEVICE_PATH;
 | |
|   ScsiDevicePath->Header.SubType   = MSG_SCSI_DP;
 | |
|   ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
 | |
|   ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
 | |
|   ScsiDevicePath->Pun              = *Target;
 | |
|   ScsiDevicePath->Lun              = (UINT16)Lun;
 | |
| 
 | |
|   *DevicePath = &ScsiDevicePath->Header;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiGetTargetLun (
 | |
|   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL               *This,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL                      *DevicePath,
 | |
|   OUT UINT8                                        **Target,
 | |
|   OUT UINT64                                       *Lun
 | |
|   )
 | |
| {
 | |
|   MPT_SCSI_DEV     *Dev;
 | |
|   SCSI_DEVICE_PATH *ScsiDevicePath;
 | |
| 
 | |
|   if (DevicePath == NULL ||
 | |
|       Target == NULL || *Target == NULL || Lun == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (DevicePath->Type    != MESSAGING_DEVICE_PATH ||
 | |
|       DevicePath->SubType != MSG_SCSI_DP) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Dev = MPT_SCSI_FROM_PASS_THRU (This);
 | |
|   ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
 | |
|   if (ScsiDevicePath->Pun > Dev->MaxTarget ||
 | |
|       ScsiDevicePath->Lun > 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (*Target, TARGET_MAX_BYTES);
 | |
|   //
 | |
|   // This device support 256 targets only, so it's enough to set the LSB
 | |
|   // of Target.
 | |
|   //
 | |
|   **Target = (UINT8)ScsiDevicePath->Pun;
 | |
|   *Lun = ScsiDevicePath->Lun;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiResetChannel (
 | |
|   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL               *This
 | |
|   )
 | |
| {
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| MptScsiExitBoot (
 | |
|   IN  EFI_EVENT Event,
 | |
|   IN  VOID      *Context
 | |
|   )
 | |
| {
 | |
|   MPT_SCSI_DEV *Dev;
 | |
| 
 | |
|   Dev = Context;
 | |
|   DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
 | |
|   MptScsiReset (Dev);
 | |
| }
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiResetTargetLun (
 | |
|   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL               *This,
 | |
|   IN UINT8                                         *Target,
 | |
|   IN UINT64                                        Lun
 | |
|   )
 | |
| {
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| //
 | |
| // Driver Binding
 | |
| //
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiControllerSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL            *This,
 | |
|   IN EFI_HANDLE                             ControllerHandle,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL               *RemainingDevicePath OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
|   PCI_TYPE00          Pci;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **)&PciIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = PciIo->Pci.Read (
 | |
|                         PciIo,
 | |
|                         EfiPciIoWidthUint32,
 | |
|                         0,
 | |
|                         sizeof (Pci) / sizeof (UINT32),
 | |
|                         &Pci
 | |
|                         );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   if (Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID &&
 | |
|       (Pci.Hdr.DeviceId == LSI_53C1030_PCI_DEVICE_ID ||
 | |
|        Pci.Hdr.DeviceId == LSI_SAS1068_PCI_DEVICE_ID ||
 | |
|        Pci.Hdr.DeviceId == LSI_SAS1068E_PCI_DEVICE_ID)) {
 | |
|     Status = EFI_SUCCESS;
 | |
|   } else {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   gBS->CloseProtocol (
 | |
|          ControllerHandle,
 | |
|          &gEfiPciIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          ControllerHandle
 | |
|          );
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiControllerStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL            *This,
 | |
|   IN EFI_HANDLE                             ControllerHandle,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL               *RemainingDevicePath OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS           Status;
 | |
|   MPT_SCSI_DEV         *Dev;
 | |
|   UINTN                Pages;
 | |
|   UINTN                BytesMapped;
 | |
| 
 | |
|   Dev = AllocateZeroPool (sizeof (*Dev));
 | |
|   if (Dev == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Dev->Signature = MPT_SCSI_DEV_SIGNATURE;
 | |
| 
 | |
|   Dev->MaxTarget = PcdGet8 (PcdMptScsiMaxTargetLimit);
 | |
|   Dev->StallPerPollUsec = PcdGet32 (PcdMptScsiStallPerPollUsec);
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **)&Dev->PciIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto FreePool;
 | |
|   }
 | |
| 
 | |
|   Status = Dev->PciIo->Attributes (
 | |
|                          Dev->PciIo,
 | |
|                          EfiPciIoAttributeOperationGet,
 | |
|                          0,
 | |
|                          &Dev->OriginalPciAttributes
 | |
|                          );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto CloseProtocol;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Enable I/O Space & Bus-Mastering
 | |
|   //
 | |
|   Status = Dev->PciIo->Attributes (
 | |
|                          Dev->PciIo,
 | |
|                          EfiPciIoAttributeOperationEnable,
 | |
|                          (EFI_PCI_IO_ATTRIBUTE_IO |
 | |
|                           EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
 | |
|                          NULL
 | |
|                          );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto CloseProtocol;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Signal device supports 64-bit DMA addresses
 | |
|   //
 | |
|   Status = Dev->PciIo->Attributes (
 | |
|                          Dev->PciIo,
 | |
|                          EfiPciIoAttributeOperationEnable,
 | |
|                          EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
 | |
|                          NULL
 | |
|                          );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Warn user that device will only be using 32-bit DMA addresses.
 | |
|     //
 | |
|     // Note that this does not prevent the device/driver from working
 | |
|     // and therefore we only warn and continue as usual.
 | |
|     //
 | |
|     DEBUG ((
 | |
|       DEBUG_WARN,
 | |
|       "%a: failed to enable 64-bit DMA addresses\n",
 | |
|       __FUNCTION__
 | |
|       ));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create buffers for data transfer
 | |
|   //
 | |
|   Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));
 | |
|   Status = Dev->PciIo->AllocateBuffer (
 | |
|                          Dev->PciIo,
 | |
|                          AllocateAnyPages,
 | |
|                          EfiBootServicesData,
 | |
|                          Pages,
 | |
|                          (VOID **)&Dev->Dma,
 | |
|                          EFI_PCI_ATTRIBUTE_MEMORY_CACHED
 | |
|                          );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto RestoreAttributes;
 | |
|   }
 | |
| 
 | |
|   BytesMapped = EFI_PAGES_TO_SIZE (Pages);
 | |
|   Status = Dev->PciIo->Map (
 | |
|                          Dev->PciIo,
 | |
|                          EfiPciIoOperationBusMasterCommonBuffer,
 | |
|                          Dev->Dma,
 | |
|                          &BytesMapped,
 | |
|                          &Dev->DmaPhysical,
 | |
|                          &Dev->DmaMapping
 | |
|                          );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto FreeBuffer;
 | |
|   }
 | |
| 
 | |
|   if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Unmap;
 | |
|   }
 | |
| 
 | |
|   Status = MptScsiInit (Dev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Unmap;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_SIGNAL_EXIT_BOOT_SERVICES,
 | |
|                   TPL_CALLBACK,
 | |
|                   &MptScsiExitBoot,
 | |
|                   Dev,
 | |
|                   &Dev->ExitBoot
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto UninitDev;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Host adapter channel, doesn't exist
 | |
|   //
 | |
|   Dev->PassThruMode.AdapterId = MAX_UINT32;
 | |
|   Dev->PassThruMode.Attributes =
 | |
|     EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
 | |
|     EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
 | |
| 
 | |
|   Dev->PassThru.Mode = &Dev->PassThruMode;
 | |
|   Dev->PassThru.PassThru = &MptScsiPassThru;
 | |
|   Dev->PassThru.GetNextTargetLun = &MptScsiGetNextTargetLun;
 | |
|   Dev->PassThru.BuildDevicePath = &MptScsiBuildDevicePath;
 | |
|   Dev->PassThru.GetTargetLun = &MptScsiGetTargetLun;
 | |
|   Dev->PassThru.ResetChannel = &MptScsiResetChannel;
 | |
|   Dev->PassThru.ResetTargetLun = &MptScsiResetTargetLun;
 | |
|   Dev->PassThru.GetNextTarget = &MptScsiGetNextTarget;
 | |
| 
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &ControllerHandle,
 | |
|                   &gEfiExtScsiPassThruProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &Dev->PassThru
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto CloseExitBoot;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| CloseExitBoot:
 | |
|   gBS->CloseEvent (Dev->ExitBoot);
 | |
| 
 | |
| UninitDev:
 | |
|   MptScsiReset (Dev);
 | |
| 
 | |
| Unmap:
 | |
|   Dev->PciIo->Unmap (
 | |
|                 Dev->PciIo,
 | |
|                 Dev->DmaMapping
 | |
|                 );
 | |
| 
 | |
| FreeBuffer:
 | |
|   Dev->PciIo->FreeBuffer (
 | |
|                 Dev->PciIo,
 | |
|                 Pages,
 | |
|                 Dev->Dma
 | |
|                 );
 | |
| 
 | |
| RestoreAttributes:
 | |
|   Dev->PciIo->Attributes (
 | |
|                 Dev->PciIo,
 | |
|                 EfiPciIoAttributeOperationSet,
 | |
|                 Dev->OriginalPciAttributes,
 | |
|                 NULL
 | |
|                 );
 | |
| 
 | |
| CloseProtocol:
 | |
|   gBS->CloseProtocol (
 | |
|          ControllerHandle,
 | |
|          &gEfiPciIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          ControllerHandle
 | |
|          );
 | |
| 
 | |
| FreePool:
 | |
|   FreePool (Dev);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiControllerStop (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL            *This,
 | |
|   IN  EFI_HANDLE                            ControllerHandle,
 | |
|   IN  UINTN                                 NumberOfChildren,
 | |
|   IN  EFI_HANDLE                            *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
 | |
|   MPT_SCSI_DEV                    *Dev;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiExtScsiPassThruProtocolGuid,
 | |
|                   (VOID **)&PassThru,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Dev = MPT_SCSI_FROM_PASS_THRU (PassThru);
 | |
| 
 | |
|   Status = gBS->UninstallProtocolInterface (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiExtScsiPassThruProtocolGuid,
 | |
|                   &Dev->PassThru
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   gBS->CloseEvent (Dev->ExitBoot);
 | |
| 
 | |
|   MptScsiReset (Dev);
 | |
| 
 | |
|   Dev->PciIo->Unmap (
 | |
|                 Dev->PciIo,
 | |
|                 Dev->DmaMapping
 | |
|                 );
 | |
| 
 | |
|   Dev->PciIo->FreeBuffer (
 | |
|                 Dev->PciIo,
 | |
|                 EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),
 | |
|                 Dev->Dma
 | |
|                 );
 | |
| 
 | |
|   Dev->PciIo->Attributes (
 | |
|                 Dev->PciIo,
 | |
|                 EfiPciIoAttributeOperationSet,
 | |
|                 Dev->OriginalPciAttributes,
 | |
|                 NULL
 | |
|                 );
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          ControllerHandle,
 | |
|          &gEfiPciIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          ControllerHandle
 | |
|          );
 | |
| 
 | |
|   FreePool (Dev);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding = {
 | |
|   &MptScsiControllerSupported,
 | |
|   &MptScsiControllerStart,
 | |
|   &MptScsiControllerStop,
 | |
|   MPT_SCSI_BINDING_VERSION,
 | |
|   NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
 | |
|   NULL, // DriverBindingHandle, filled as well
 | |
| };
 | |
| 
 | |
| //
 | |
| // Component Name
 | |
| //
 | |
| 
 | |
| STATIC
 | |
| EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
 | |
|   { "eng;en", L"LSI Fusion MPT SCSI Driver" },
 | |
|   { NULL,     NULL                   }
 | |
| };
 | |
| 
 | |
| STATIC
 | |
| EFI_COMPONENT_NAME_PROTOCOL mComponentName;
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiGetDriverName (
 | |
|   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
 | |
|   IN  CHAR8                       *Language,
 | |
|   OUT CHAR16                      **DriverName
 | |
|   )
 | |
| {
 | |
|   return LookupUnicodeString2 (
 | |
|            Language,
 | |
|            This->SupportedLanguages,
 | |
|            mDriverNameTable,
 | |
|            DriverName,
 | |
|            (BOOLEAN)(This == &mComponentName) // Iso639Language
 | |
|            );
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiGetDeviceName (
 | |
|   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
 | |
|   IN  EFI_HANDLE                  DeviceHandle,
 | |
|   IN  EFI_HANDLE                  ChildHandle,
 | |
|   IN  CHAR8                       *Language,
 | |
|   OUT CHAR16                      **ControllerName
 | |
|   )
 | |
| {
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
 | |
|   &MptScsiGetDriverName,
 | |
|   &MptScsiGetDeviceName,
 | |
|   "eng" // SupportedLanguages, ISO 639-2 language codes
 | |
| };
 | |
| 
 | |
| STATIC
 | |
| EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
 | |
|   (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &MptScsiGetDriverName,
 | |
|   (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &MptScsiGetDeviceName,
 | |
|   "en" // SupportedLanguages, RFC 4646 language codes
 | |
| };
 | |
| 
 | |
| //
 | |
| // Entry Point
 | |
| //
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MptScsiEntryPoint (
 | |
|   IN EFI_HANDLE       ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE *SystemTable
 | |
|   )
 | |
| {
 | |
|   return EfiLibInstallDriverBindingComponentName2 (
 | |
|            ImageHandle,
 | |
|            SystemTable,
 | |
|            &mMptScsiDriverBinding,
 | |
|            ImageHandle, // The handle to install onto
 | |
|            &mComponentName,
 | |
|            &mComponentName2
 | |
|            );
 | |
| }
 |