3 This driver produces Extended SCSI Pass Thru Protocol instances for
4 LSI Fusion MPT SCSI devices.
6 Copyright (C) 2020, Oracle and/or its affiliates.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <IndustryStandard/FusionMptScsi.h>
13 #include <IndustryStandard/Pci.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiLib.h>
21 #include <Protocol/PciIo.h>
22 #include <Protocol/PciRootBridgeIo.h>
23 #include <Protocol/ScsiPassThruExt.h>
24 #include <Uefi/UefiSpec.h>
27 // Higher versions will be used before lower, 0x10-0xffffffef is the version
28 // range for IVH (Indie Hardware Vendors)
30 #define MPT_SCSI_BINDING_VERSION 0x10
37 MPT_SCSI_REQUEST_ALIGNED IoRequest
;
38 MPT_SCSI_IO_REPLY_ALIGNED IoReply
;
40 // As EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.SenseDataLength is defined
41 // as UINT8, defining here SenseData size to MAX_UINT8 will guarantee it
42 // cannot overflow when passed to device.
44 UINT8 Sense
[MAX_UINT8
];
46 // This size of the data is arbitrarily chosen.
47 // It seems to be sufficient for all I/O requests sent through
48 // EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() for common boot scenarios.
51 } MPT_SCSI_DMA_BUFFER
;
53 #define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
56 EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru
;
57 EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode
;
59 UINT32 StallPerPollUsec
;
60 EFI_PCI_IO_PROTOCOL
*PciIo
;
61 UINT64 OriginalPciAttributes
;
62 MPT_SCSI_DMA_BUFFER
*Dma
;
63 EFI_PHYSICAL_ADDRESS DmaPhysical
;
65 BOOLEAN IoReplyEnqueued
;
68 #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
69 CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
71 #define MPT_SCSI_DMA_ADDR(Dev, MemberName) \
72 (Dev->DmaPhysical + OFFSET_OF (MPT_SCSI_DMA_BUFFER, MemberName))
74 #define MPT_SCSI_DMA_ADDR_HIGH(Dev, MemberName) \
75 ((UINT32)RShiftU64 (MPT_SCSI_DMA_ADDR (Dev, MemberName), 32))
77 #define MPT_SCSI_DMA_ADDR_LOW(Dev, MemberName) \
78 ((UINT32)MPT_SCSI_DMA_ADDR (Dev, MemberName))
92 return Dev
->PciIo
->Io
.Write (
105 IN MPT_SCSI_DEV
*Dev
,
110 return Dev
->PciIo
->Io
.Read (
123 IN MPT_SCSI_DEV
*Dev
,
124 IN UINT8 DoorbellFunc
,
131 (((UINT32
)DoorbellFunc
) << 24) | (DoorbellArg
<< 16)
146 Status
= MptDoorbell (Dev
, MPT_DOORBELL_RESET
, 0);
147 if (EFI_ERROR (Status
)) {
153 Status
= Out32 (Dev
, MPT_REG_IMASK
, MPT_IMASK_DOORBELL
| MPT_IMASK_REPLY
);
154 if (EFI_ERROR (Status
)) {
158 // Clear interrupt status
160 Status
= Out32 (Dev
, MPT_REG_ISTATUS
, 0);
161 if (EFI_ERROR (Status
)) {
176 MPT_IO_CONTROLLER_INIT_REQUEST Data
;
179 MPT_IO_CONTROLLER_INIT_REQUEST
*Req
;
180 MPT_IO_CONTROLLER_INIT_REPLY Reply
;
184 Req
= &AlignedReq
.Data
;
186 Status
= MptScsiReset (Dev
);
187 if (EFI_ERROR (Status
)) {
191 ZeroMem (Req
, sizeof (*Req
));
192 ZeroMem (&Reply
, sizeof (Reply
));
193 Req
->WhoInit
= MPT_IOC_WHOINIT_ROM_BIOS
;
194 Req
->Function
= MPT_MESSAGE_HDR_FUNCTION_IOC_INIT
;
196 FixedPcdGet8 (PcdMptScsiMaxTargetLimit
) < 255,
197 "Req supports 255 targets only (max target is 254)"
199 Req
->MaxDevices
= Dev
->MaxTarget
+ 1;
201 Req
->ReplyFrameSize
= sizeof Dev
->Dma
->IoReply
.Data
;
202 Req
->HostMfaHighAddr
= MPT_SCSI_DMA_ADDR_HIGH (Dev
, IoRequest
);
203 Req
->SenseBufferHighAddr
= MPT_SCSI_DMA_ADDR_HIGH (Dev
, Sense
);
206 // Send controller init through doorbell
209 sizeof (*Req
) % sizeof (UINT32
) == 0,
210 "Req must be multiple of UINT32"
213 sizeof (*Req
) / sizeof (UINT32
) <= MAX_UINT8
,
214 "Req must fit in MAX_UINT8 Dwords"
216 Status
= MptDoorbell (
218 MPT_DOORBELL_HANDSHAKE
,
219 (UINT8
)(sizeof (*Req
) / sizeof (UINT32
))
221 if (EFI_ERROR (Status
)) {
224 Status
= Dev
->PciIo
->Io
.Write (
226 EfiPciIoWidthFifoUint32
,
229 sizeof (*Req
) / sizeof (UINT32
),
232 if (EFI_ERROR (Status
)) {
237 // Read reply through doorbell
238 // Each 32bit (Dword) read produces 16bit (Word) of data
240 // The reply is read back to complete the doorbell function but it
241 // isn't useful because it doesn't contain relevant data or status
245 sizeof (Reply
) % sizeof (UINT16
) == 0,
246 "Reply must be multiple of UINT16"
248 ReplyBytes
= (UINT8
*)&Reply
;
249 while (ReplyBytes
!= (UINT8
*)(&Reply
+ 1)) {
250 Status
= In32 (Dev
, MPT_REG_DOORBELL
, &ReplyWord
);
251 if (EFI_ERROR (Status
)) {
254 CopyMem (ReplyBytes
, &ReplyWord
, sizeof (UINT16
));
255 ReplyBytes
+= sizeof (UINT16
);
259 // Clear interrupts generated by doorbell reply
261 Status
= Out32 (Dev
, MPT_REG_ISTATUS
, 0);
262 if (EFI_ERROR (Status
)) {
271 ReportHostAdapterError (
272 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
275 DEBUG ((DEBUG_ERROR
, "%a: fatal error in scsi request\n", __FUNCTION__
));
276 Packet
->InTransferLength
= 0;
277 Packet
->OutTransferLength
= 0;
278 Packet
->SenseDataLength
= 0;
279 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
280 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED
;
281 return EFI_DEVICE_ERROR
;
286 ReportHostAdapterOverrunError (
287 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
290 Packet
->SenseDataLength
= 0;
291 Packet
->HostAdapterStatus
=
292 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
293 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
294 return EFI_BAD_BUFFER_SIZE
;
299 MptScsiPopulateRequest (
300 IN MPT_SCSI_DEV
*Dev
,
303 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
306 MPT_SCSI_REQUEST_WITH_SG
*Request
;
308 Request
= &Dev
->Dma
->IoRequest
.Data
;
310 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
||
311 (Packet
->InTransferLength
> 0 && Packet
->OutTransferLength
> 0) ||
312 Packet
->CdbLength
> sizeof (Request
->Header
.Cdb
)) {
313 return EFI_UNSUPPORTED
;
316 if (Target
> Dev
->MaxTarget
|| Lun
> 0 ||
317 Packet
->DataDirection
> EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
||
319 // Trying to receive, but destination pointer is NULL, or contradicting
320 // transfer direction
322 (Packet
->InTransferLength
> 0 &&
323 (Packet
->InDataBuffer
== NULL
||
324 Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_WRITE
329 // Trying to send, but source pointer is NULL, or contradicting transfer
332 (Packet
->OutTransferLength
> 0 &&
333 (Packet
->OutDataBuffer
== NULL
||
334 Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
338 return EFI_INVALID_PARAMETER
;
341 if (Packet
->InTransferLength
> sizeof (Dev
->Dma
->Data
)) {
342 Packet
->InTransferLength
= sizeof (Dev
->Dma
->Data
);
343 return ReportHostAdapterOverrunError (Packet
);
345 if (Packet
->OutTransferLength
> sizeof (Dev
->Dma
->Data
)) {
346 Packet
->OutTransferLength
= sizeof (Dev
->Dma
->Data
);
347 return ReportHostAdapterOverrunError (Packet
);
350 ZeroMem (Request
, sizeof (*Request
));
351 Request
->Header
.TargetId
= Target
;
353 // Only LUN 0 is currently supported, hence the cast is safe
355 Request
->Header
.Lun
[1] = (UINT8
)Lun
;
356 Request
->Header
.Function
= MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST
;
357 Request
->Header
.MessageContext
= 1; // We handle one request at a time
359 Request
->Header
.CdbLength
= Packet
->CdbLength
;
360 CopyMem (Request
->Header
.Cdb
, Packet
->Cdb
, Packet
->CdbLength
);
363 // SenseDataLength is UINT8, Sense[] is MAX_UINT8, so we can't overflow
365 ZeroMem (Dev
->Dma
->Sense
, Packet
->SenseDataLength
);
366 Request
->Header
.SenseBufferLength
= Packet
->SenseDataLength
;
367 Request
->Header
.SenseBufferLowAddress
= MPT_SCSI_DMA_ADDR_LOW (Dev
, Sense
);
369 Request
->Sg
.EndOfList
= 1;
370 Request
->Sg
.EndOfBuffer
= 1;
371 Request
->Sg
.LastElement
= 1;
372 Request
->Sg
.ElementType
= MPT_SG_ENTRY_TYPE_SIMPLE
;
373 Request
->Sg
.Is64BitAddress
= 1;
374 Request
->Sg
.DataBufferAddress
= MPT_SCSI_DMA_ADDR (Dev
, Data
);
377 // "MPT_SG_ENTRY_SIMPLE.Length" is a 24-bit quantity.
380 sizeof (Dev
->Dma
->Data
) < SIZE_16MB
,
381 "MPT_SCSI_DMA_BUFFER.Data must be smaller than 16MB"
384 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
385 Request
->Header
.DataLength
= Packet
->InTransferLength
;
386 Request
->Sg
.Length
= Packet
->InTransferLength
;
387 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ
;
389 Request
->Header
.DataLength
= Packet
->OutTransferLength
;
390 Request
->Sg
.Length
= Packet
->OutTransferLength
;
391 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE
;
393 CopyMem (Dev
->Dma
->Data
, Packet
->OutDataBuffer
, Packet
->OutTransferLength
);
394 Request
->Sg
.BufferContainsData
= 1;
397 if (Request
->Header
.DataLength
== 0) {
398 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE
;
407 IN MPT_SCSI_DEV
*Dev
,
408 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
413 if (!Dev
->IoReplyEnqueued
) {
415 // Put one free reply frame on the reply queue, the hardware may use it to
416 // report an error to us.
418 Status
= Out32 (Dev
, MPT_REG_REP_Q
, MPT_SCSI_DMA_ADDR_LOW (Dev
, IoReply
));
419 if (EFI_ERROR (Status
)) {
420 return EFI_DEVICE_ERROR
;
422 Dev
->IoReplyEnqueued
= TRUE
;
425 Status
= Out32 (Dev
, MPT_REG_REQ_Q
, MPT_SCSI_DMA_ADDR_LOW (Dev
, IoRequest
));
426 if (EFI_ERROR (Status
)) {
427 return EFI_DEVICE_ERROR
;
436 IN MPT_SCSI_DEV
*Dev
,
445 // Timeouts are not supported for
446 // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() in this implementation.
449 Status
= In32 (Dev
, MPT_REG_ISTATUS
, &Istatus
);
450 if (EFI_ERROR (Status
)) {
457 if (Istatus
& MPT_IMASK_REPLY
) {
461 gBS
->Stall (Dev
->StallPerPollUsec
);
464 Status
= In32 (Dev
, MPT_REG_REP_Q
, Reply
);
465 if (EFI_ERROR (Status
)) {
470 // The driver is supposed to fetch replies until 0xffffffff is returned, which
471 // will reset the interrupt status. We put only one request, so we expect the
472 // next read reply to be the last.
474 Status
= In32 (Dev
, MPT_REG_REP_Q
, &EmptyReply
);
475 if (EFI_ERROR (Status
) || EmptyReply
!= MAX_UINT32
) {
476 return EFI_DEVICE_ERROR
;
485 IN MPT_SCSI_DEV
*Dev
,
487 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
490 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
491 CopyMem (Packet
->InDataBuffer
, Dev
->Dma
->Data
, Packet
->InTransferLength
);
494 if (Reply
== Dev
->Dma
->IoRequest
.Data
.Header
.MessageContext
) {
496 // This is a turbo reply, everything is good
498 Packet
->SenseDataLength
= 0;
499 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
500 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
502 } else if ((Reply
& BIT31
) != 0) {
503 DEBUG ((DEBUG_INFO
, "%a: Full reply returned\n", __FUNCTION__
));
505 // When reply MSB is set, we got a full reply. Since we submitted only one
506 // reply frame, we know it's IoReply.
508 Dev
->IoReplyEnqueued
= FALSE
;
510 Packet
->TargetStatus
= Dev
->Dma
->IoReply
.Data
.ScsiStatus
;
512 // Make sure device only lowers SenseDataLength before copying sense
514 ASSERT (Dev
->Dma
->IoReply
.Data
.SenseCount
<= Packet
->SenseDataLength
);
515 Packet
->SenseDataLength
=
516 (UINT8
)MIN (Dev
->Dma
->IoReply
.Data
.SenseCount
, Packet
->SenseDataLength
);
517 CopyMem (Packet
->SenseData
, Dev
->Dma
->Sense
, Packet
->SenseDataLength
);
519 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
520 Packet
->InTransferLength
= Dev
->Dma
->IoReply
.Data
.TransferCount
;
522 Packet
->OutTransferLength
= Dev
->Dma
->IoReply
.Data
.TransferCount
;
525 switch (Dev
->Dma
->IoReply
.Data
.IocStatus
) {
526 case MPT_SCSI_IOCSTATUS_SUCCESS
:
527 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
529 case MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE
:
530 Packet
->HostAdapterStatus
=
531 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
;
533 case MPT_SCSI_IOCSTATUS_DATA_UNDERRUN
:
534 case MPT_SCSI_IOCSTATUS_DATA_OVERRUN
:
535 Packet
->HostAdapterStatus
=
536 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
539 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
540 return EFI_DEVICE_ERROR
;
544 DEBUG ((DEBUG_ERROR
, "%a: unexpected reply (%x)\n", __FUNCTION__
, Reply
));
545 return ReportHostAdapterError (Packet
);
552 // Ext SCSI Pass Thru
559 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
562 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
563 IN EFI_EVENT Event OPTIONAL
570 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
572 // We only use first byte of target identifer
574 Status
= MptScsiPopulateRequest (Dev
, *Target
, Lun
, Packet
);
575 if (EFI_ERROR (Status
)) {
577 // MptScsiPopulateRequest modified packet according to the error
582 Status
= MptScsiSendRequest (Dev
, Packet
);
583 if (EFI_ERROR (Status
)) {
584 return ReportHostAdapterError (Packet
);
587 Status
= MptScsiGetReply (Dev
, &Reply
);
588 if (EFI_ERROR (Status
)) {
589 return ReportHostAdapterError (Packet
);
592 return MptScsiHandleReply (Dev
, Reply
, Packet
);
597 IsTargetInitialized (
603 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
; ++Idx
) {
604 if (Target
[Idx
] != 0xFF) {
614 MptScsiGetNextTargetLun (
615 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
616 IN OUT UINT8
**Target
,
622 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
624 // Currently support only LUN 0, so hardcode it
626 if (!IsTargetInitialized (*Target
)) {
627 ZeroMem (*Target
, TARGET_MAX_BYTES
);
629 } else if (**Target
> Dev
->MaxTarget
|| *Lun
> 0) {
630 return EFI_INVALID_PARAMETER
;
631 } else if (**Target
< Dev
->MaxTarget
) {
633 // This device interface support 256 targets only, so it's enough to
634 // increment the LSB of Target, as it will never overflow.
638 return EFI_NOT_FOUND
;
647 MptScsiGetNextTarget (
648 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
649 IN OUT UINT8
**Target
654 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
655 if (!IsTargetInitialized (*Target
)) {
656 ZeroMem (*Target
, TARGET_MAX_BYTES
);
657 } else if (**Target
> Dev
->MaxTarget
) {
658 return EFI_INVALID_PARAMETER
;
659 } else if (**Target
< Dev
->MaxTarget
) {
661 // This device interface support 256 targets only, so it's enough to
662 // increment the LSB of Target, as it will never overflow.
666 return EFI_NOT_FOUND
;
675 MptScsiBuildDevicePath (
676 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
679 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
683 SCSI_DEVICE_PATH
*ScsiDevicePath
;
685 if (DevicePath
== NULL
) {
686 return EFI_INVALID_PARAMETER
;
690 // This device support 256 targets only, so it's enough to dereference
691 // the LSB of Target.
693 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
694 if (*Target
> Dev
->MaxTarget
|| Lun
> 0) {
695 return EFI_NOT_FOUND
;
698 ScsiDevicePath
= AllocateZeroPool (sizeof (*ScsiDevicePath
));
699 if (ScsiDevicePath
== NULL
) {
700 return EFI_OUT_OF_RESOURCES
;
703 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
704 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
705 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof (*ScsiDevicePath
);
706 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof (*ScsiDevicePath
) >> 8);
707 ScsiDevicePath
->Pun
= *Target
;
708 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
710 *DevicePath
= &ScsiDevicePath
->Header
;
717 MptScsiGetTargetLun (
718 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
719 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
725 SCSI_DEVICE_PATH
*ScsiDevicePath
;
727 if (DevicePath
== NULL
||
728 Target
== NULL
|| *Target
== NULL
|| Lun
== NULL
) {
729 return EFI_INVALID_PARAMETER
;
732 if (DevicePath
->Type
!= MESSAGING_DEVICE_PATH
||
733 DevicePath
->SubType
!= MSG_SCSI_DP
) {
734 return EFI_UNSUPPORTED
;
737 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
738 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
739 if (ScsiDevicePath
->Pun
> Dev
->MaxTarget
||
740 ScsiDevicePath
->Lun
> 0) {
741 return EFI_NOT_FOUND
;
744 ZeroMem (*Target
, TARGET_MAX_BYTES
);
746 // This device support 256 targets only, so it's enough to set the LSB
749 **Target
= (UINT8
)ScsiDevicePath
->Pun
;
750 *Lun
= ScsiDevicePath
->Lun
;
758 MptScsiResetChannel (
759 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
762 return EFI_UNSUPPORTED
;
768 MptScsiResetTargetLun (
769 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
774 return EFI_UNSUPPORTED
;
784 MptScsiControllerSupported (
785 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
786 IN EFI_HANDLE ControllerHandle
,
787 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
791 EFI_PCI_IO_PROTOCOL
*PciIo
;
794 Status
= gBS
->OpenProtocol (
796 &gEfiPciIoProtocolGuid
,
798 This
->DriverBindingHandle
,
800 EFI_OPEN_PROTOCOL_BY_DRIVER
802 if (EFI_ERROR (Status
)) {
806 Status
= PciIo
->Pci
.Read (
810 sizeof (Pci
) / sizeof (UINT32
),
813 if (EFI_ERROR (Status
)) {
817 if (Pci
.Hdr
.VendorId
== LSI_LOGIC_PCI_VENDOR_ID
&&
818 (Pci
.Hdr
.DeviceId
== LSI_53C1030_PCI_DEVICE_ID
||
819 Pci
.Hdr
.DeviceId
== LSI_SAS1068_PCI_DEVICE_ID
||
820 Pci
.Hdr
.DeviceId
== LSI_SAS1068E_PCI_DEVICE_ID
)) {
821 Status
= EFI_SUCCESS
;
823 Status
= EFI_UNSUPPORTED
;
829 &gEfiPciIoProtocolGuid
,
830 This
->DriverBindingHandle
,
839 MptScsiControllerStart (
840 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
841 IN EFI_HANDLE ControllerHandle
,
842 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
850 Dev
= AllocateZeroPool (sizeof (*Dev
));
852 return EFI_OUT_OF_RESOURCES
;
855 Dev
->Signature
= MPT_SCSI_DEV_SIGNATURE
;
857 Dev
->MaxTarget
= PcdGet8 (PcdMptScsiMaxTargetLimit
);
858 Dev
->StallPerPollUsec
= PcdGet32 (PcdMptScsiStallPerPollUsec
);
860 Status
= gBS
->OpenProtocol (
862 &gEfiPciIoProtocolGuid
,
863 (VOID
**)&Dev
->PciIo
,
864 This
->DriverBindingHandle
,
866 EFI_OPEN_PROTOCOL_BY_DRIVER
868 if (EFI_ERROR (Status
)) {
872 Status
= Dev
->PciIo
->Attributes (
874 EfiPciIoAttributeOperationGet
,
876 &Dev
->OriginalPciAttributes
878 if (EFI_ERROR (Status
)) {
883 // Enable I/O Space & Bus-Mastering
885 Status
= Dev
->PciIo
->Attributes (
887 EfiPciIoAttributeOperationEnable
,
888 (EFI_PCI_IO_ATTRIBUTE_IO
|
889 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
892 if (EFI_ERROR (Status
)) {
897 // Signal device supports 64-bit DMA addresses
899 Status
= Dev
->PciIo
->Attributes (
901 EfiPciIoAttributeOperationEnable
,
902 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
905 if (EFI_ERROR (Status
)) {
907 // Warn user that device will only be using 32-bit DMA addresses.
909 // Note that this does not prevent the device/driver from working
910 // and therefore we only warn and continue as usual.
914 "%a: failed to enable 64-bit DMA addresses\n",
920 // Create buffers for data transfer
922 Pages
= EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
));
923 Status
= Dev
->PciIo
->AllocateBuffer (
929 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
931 if (EFI_ERROR (Status
)) {
932 goto RestoreAttributes
;
935 BytesMapped
= EFI_PAGES_TO_SIZE (Pages
);
936 Status
= Dev
->PciIo
->Map (
938 EfiPciIoOperationBusMasterCommonBuffer
,
944 if (EFI_ERROR (Status
)) {
948 if (BytesMapped
!= EFI_PAGES_TO_SIZE (Pages
)) {
949 Status
= EFI_OUT_OF_RESOURCES
;
953 Status
= MptScsiInit (Dev
);
954 if (EFI_ERROR (Status
)) {
959 // Host adapter channel, doesn't exist
961 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
962 Dev
->PassThruMode
.Attributes
=
963 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
964 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
966 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
967 Dev
->PassThru
.PassThru
= &MptScsiPassThru
;
968 Dev
->PassThru
.GetNextTargetLun
= &MptScsiGetNextTargetLun
;
969 Dev
->PassThru
.BuildDevicePath
= &MptScsiBuildDevicePath
;
970 Dev
->PassThru
.GetTargetLun
= &MptScsiGetTargetLun
;
971 Dev
->PassThru
.ResetChannel
= &MptScsiResetChannel
;
972 Dev
->PassThru
.ResetTargetLun
= &MptScsiResetTargetLun
;
973 Dev
->PassThru
.GetNextTarget
= &MptScsiGetNextTarget
;
975 Status
= gBS
->InstallProtocolInterface (
977 &gEfiExtScsiPassThruProtocolGuid
,
978 EFI_NATIVE_INTERFACE
,
981 if (EFI_ERROR (Status
)) {
997 Dev
->PciIo
->FreeBuffer (
1004 Dev
->PciIo
->Attributes (
1006 EfiPciIoAttributeOperationSet
,
1007 Dev
->OriginalPciAttributes
,
1012 gBS
->CloseProtocol (
1014 &gEfiPciIoProtocolGuid
,
1015 This
->DriverBindingHandle
,
1028 MptScsiControllerStop (
1029 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1030 IN EFI_HANDLE ControllerHandle
,
1031 IN UINTN NumberOfChildren
,
1032 IN EFI_HANDLE
*ChildHandleBuffer
1036 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
1039 Status
= gBS
->OpenProtocol (
1041 &gEfiExtScsiPassThruProtocolGuid
,
1043 This
->DriverBindingHandle
,
1045 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
1047 if (EFI_ERROR (Status
)) {
1051 Dev
= MPT_SCSI_FROM_PASS_THRU (PassThru
);
1053 Status
= gBS
->UninstallProtocolInterface (
1055 &gEfiExtScsiPassThruProtocolGuid
,
1058 if (EFI_ERROR (Status
)) {
1069 Dev
->PciIo
->FreeBuffer (
1071 EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
)),
1075 Dev
->PciIo
->Attributes (
1077 EfiPciIoAttributeOperationSet
,
1078 Dev
->OriginalPciAttributes
,
1082 gBS
->CloseProtocol (
1084 &gEfiPciIoProtocolGuid
,
1085 This
->DriverBindingHandle
,
1095 EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding
= {
1096 &MptScsiControllerSupported
,
1097 &MptScsiControllerStart
,
1098 &MptScsiControllerStop
,
1099 MPT_SCSI_BINDING_VERSION
,
1100 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
1101 NULL
, // DriverBindingHandle, filled as well
1109 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1110 { "eng;en", L
"LSI Fusion MPT SCSI Driver" },
1115 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1119 MptScsiGetDriverName (
1120 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1122 OUT CHAR16
**DriverName
1125 return LookupUnicodeString2 (
1127 This
->SupportedLanguages
,
1130 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1136 MptScsiGetDeviceName (
1137 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1138 IN EFI_HANDLE DeviceHandle
,
1139 IN EFI_HANDLE ChildHandle
,
1141 OUT CHAR16
**ControllerName
1144 return EFI_UNSUPPORTED
;
1148 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1149 &MptScsiGetDriverName
,
1150 &MptScsiGetDeviceName
,
1151 "eng" // SupportedLanguages, ISO 639-2 language codes
1155 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1156 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &MptScsiGetDriverName
,
1157 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &MptScsiGetDeviceName
,
1158 "en" // SupportedLanguages, RFC 4646 language codes
1168 IN EFI_HANDLE ImageHandle
,
1169 IN EFI_SYSTEM_TABLE
*SystemTable
1172 return EfiLibInstallDriverBindingComponentName2 (
1175 &mMptScsiDriverBinding
,
1176 ImageHandle
, // The handle to install onto