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
;
63 MPT_SCSI_DMA_BUFFER
*Dma
;
64 EFI_PHYSICAL_ADDRESS DmaPhysical
;
66 BOOLEAN IoReplyEnqueued
;
69 #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
70 CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
72 #define MPT_SCSI_DMA_ADDR(Dev, MemberName) \
73 (Dev->DmaPhysical + OFFSET_OF (MPT_SCSI_DMA_BUFFER, MemberName))
75 #define MPT_SCSI_DMA_ADDR_HIGH(Dev, MemberName) \
76 ((UINT32)RShiftU64 (MPT_SCSI_DMA_ADDR (Dev, MemberName), 32))
78 #define MPT_SCSI_DMA_ADDR_LOW(Dev, MemberName) \
79 ((UINT32)MPT_SCSI_DMA_ADDR (Dev, MemberName))
93 return Dev
->PciIo
->Io
.Write (
106 IN MPT_SCSI_DEV
*Dev
,
111 return Dev
->PciIo
->Io
.Read (
124 IN MPT_SCSI_DEV
*Dev
,
125 IN UINT8 DoorbellFunc
,
132 (((UINT32
)DoorbellFunc
) << 24) | (DoorbellArg
<< 16)
147 Status
= MptDoorbell (Dev
, MPT_DOORBELL_RESET
, 0);
148 if (EFI_ERROR (Status
)) {
155 Status
= Out32 (Dev
, MPT_REG_IMASK
, MPT_IMASK_DOORBELL
| MPT_IMASK_REPLY
);
156 if (EFI_ERROR (Status
)) {
161 // Clear interrupt status
163 Status
= Out32 (Dev
, MPT_REG_ISTATUS
, 0);
164 if (EFI_ERROR (Status
)) {
180 MPT_IO_CONTROLLER_INIT_REQUEST Data
;
183 MPT_IO_CONTROLLER_INIT_REQUEST
*Req
;
184 MPT_IO_CONTROLLER_INIT_REPLY Reply
;
188 Req
= &AlignedReq
.Data
;
190 Status
= MptScsiReset (Dev
);
191 if (EFI_ERROR (Status
)) {
195 ZeroMem (Req
, sizeof (*Req
));
196 ZeroMem (&Reply
, sizeof (Reply
));
197 Req
->WhoInit
= MPT_IOC_WHOINIT_ROM_BIOS
;
198 Req
->Function
= MPT_MESSAGE_HDR_FUNCTION_IOC_INIT
;
200 FixedPcdGet8 (PcdMptScsiMaxTargetLimit
) < 255,
201 "Req supports 255 targets only (max target is 254)"
203 Req
->MaxDevices
= Dev
->MaxTarget
+ 1;
205 Req
->ReplyFrameSize
= sizeof Dev
->Dma
->IoReply
.Data
;
206 Req
->HostMfaHighAddr
= MPT_SCSI_DMA_ADDR_HIGH (Dev
, IoRequest
);
207 Req
->SenseBufferHighAddr
= MPT_SCSI_DMA_ADDR_HIGH (Dev
, Sense
);
210 // Send controller init through doorbell
213 sizeof (*Req
) % sizeof (UINT32
) == 0,
214 "Req must be multiple of UINT32"
217 sizeof (*Req
) / sizeof (UINT32
) <= MAX_UINT8
,
218 "Req must fit in MAX_UINT8 Dwords"
220 Status
= MptDoorbell (
222 MPT_DOORBELL_HANDSHAKE
,
223 (UINT8
)(sizeof (*Req
) / sizeof (UINT32
))
225 if (EFI_ERROR (Status
)) {
229 Status
= Dev
->PciIo
->Io
.Write (
231 EfiPciIoWidthFifoUint32
,
234 sizeof (*Req
) / sizeof (UINT32
),
237 if (EFI_ERROR (Status
)) {
242 // Read reply through doorbell
243 // Each 32bit (Dword) read produces 16bit (Word) of data
245 // The reply is read back to complete the doorbell function but it
246 // isn't useful because it doesn't contain relevant data or status
250 sizeof (Reply
) % sizeof (UINT16
) == 0,
251 "Reply must be multiple of UINT16"
253 ReplyBytes
= (UINT8
*)&Reply
;
254 while (ReplyBytes
!= (UINT8
*)(&Reply
+ 1)) {
255 Status
= In32 (Dev
, MPT_REG_DOORBELL
, &ReplyWord
);
256 if (EFI_ERROR (Status
)) {
260 CopyMem (ReplyBytes
, &ReplyWord
, sizeof (UINT16
));
261 ReplyBytes
+= sizeof (UINT16
);
265 // Clear interrupts generated by doorbell reply
267 Status
= Out32 (Dev
, MPT_REG_ISTATUS
, 0);
268 if (EFI_ERROR (Status
)) {
277 ReportHostAdapterError (
278 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
281 DEBUG ((DEBUG_ERROR
, "%a: fatal error in scsi request\n", __FUNCTION__
));
282 Packet
->InTransferLength
= 0;
283 Packet
->OutTransferLength
= 0;
284 Packet
->SenseDataLength
= 0;
285 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
286 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED
;
287 return EFI_DEVICE_ERROR
;
292 ReportHostAdapterOverrunError (
293 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
296 Packet
->SenseDataLength
= 0;
297 Packet
->HostAdapterStatus
=
298 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
299 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
300 return EFI_BAD_BUFFER_SIZE
;
305 MptScsiPopulateRequest (
306 IN MPT_SCSI_DEV
*Dev
,
309 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
312 MPT_SCSI_REQUEST_WITH_SG
*Request
;
314 Request
= &Dev
->Dma
->IoRequest
.Data
;
316 if ((Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
) ||
317 ((Packet
->InTransferLength
> 0) && (Packet
->OutTransferLength
> 0)) ||
318 (Packet
->CdbLength
> sizeof (Request
->Header
.Cdb
)))
320 return EFI_UNSUPPORTED
;
323 if ((Target
> Dev
->MaxTarget
) || (Lun
> 0) ||
324 (Packet
->DataDirection
> EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
) ||
326 // Trying to receive, but destination pointer is NULL, or contradicting
327 // transfer direction
329 ((Packet
->InTransferLength
> 0) &&
330 ((Packet
->InDataBuffer
== NULL
) ||
331 (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_WRITE
)
336 // Trying to send, but source pointer is NULL, or contradicting transfer
339 ((Packet
->OutTransferLength
> 0) &&
340 ((Packet
->OutDataBuffer
== NULL
) ||
341 (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
)
346 return EFI_INVALID_PARAMETER
;
349 if (Packet
->InTransferLength
> sizeof (Dev
->Dma
->Data
)) {
350 Packet
->InTransferLength
= sizeof (Dev
->Dma
->Data
);
351 return ReportHostAdapterOverrunError (Packet
);
354 if (Packet
->OutTransferLength
> sizeof (Dev
->Dma
->Data
)) {
355 Packet
->OutTransferLength
= sizeof (Dev
->Dma
->Data
);
356 return ReportHostAdapterOverrunError (Packet
);
359 ZeroMem (Request
, sizeof (*Request
));
360 Request
->Header
.TargetId
= Target
;
362 // Only LUN 0 is currently supported, hence the cast is safe
364 Request
->Header
.Lun
[1] = (UINT8
)Lun
;
365 Request
->Header
.Function
= MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST
;
366 Request
->Header
.MessageContext
= 1; // We handle one request at a time
368 Request
->Header
.CdbLength
= Packet
->CdbLength
;
369 CopyMem (Request
->Header
.Cdb
, Packet
->Cdb
, Packet
->CdbLength
);
372 // SenseDataLength is UINT8, Sense[] is MAX_UINT8, so we can't overflow
374 ZeroMem (Dev
->Dma
->Sense
, Packet
->SenseDataLength
);
375 Request
->Header
.SenseBufferLength
= Packet
->SenseDataLength
;
376 Request
->Header
.SenseBufferLowAddress
= MPT_SCSI_DMA_ADDR_LOW (Dev
, Sense
);
378 Request
->Sg
.EndOfList
= 1;
379 Request
->Sg
.EndOfBuffer
= 1;
380 Request
->Sg
.LastElement
= 1;
381 Request
->Sg
.ElementType
= MPT_SG_ENTRY_TYPE_SIMPLE
;
382 Request
->Sg
.Is64BitAddress
= 1;
383 Request
->Sg
.DataBufferAddress
= MPT_SCSI_DMA_ADDR (Dev
, Data
);
386 // "MPT_SG_ENTRY_SIMPLE.Length" is a 24-bit quantity.
389 sizeof (Dev
->Dma
->Data
) < SIZE_16MB
,
390 "MPT_SCSI_DMA_BUFFER.Data must be smaller than 16MB"
393 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
394 Request
->Header
.DataLength
= Packet
->InTransferLength
;
395 Request
->Sg
.Length
= Packet
->InTransferLength
;
396 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ
;
398 Request
->Header
.DataLength
= Packet
->OutTransferLength
;
399 Request
->Sg
.Length
= Packet
->OutTransferLength
;
400 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE
;
402 CopyMem (Dev
->Dma
->Data
, Packet
->OutDataBuffer
, Packet
->OutTransferLength
);
403 Request
->Sg
.BufferContainsData
= 1;
406 if (Request
->Header
.DataLength
== 0) {
407 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE
;
416 IN MPT_SCSI_DEV
*Dev
,
417 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
422 if (!Dev
->IoReplyEnqueued
) {
424 // Put one free reply frame on the reply queue, the hardware may use it to
425 // report an error to us.
427 Status
= Out32 (Dev
, MPT_REG_REP_Q
, MPT_SCSI_DMA_ADDR_LOW (Dev
, IoReply
));
428 if (EFI_ERROR (Status
)) {
429 return EFI_DEVICE_ERROR
;
432 Dev
->IoReplyEnqueued
= TRUE
;
435 Status
= Out32 (Dev
, MPT_REG_REQ_Q
, MPT_SCSI_DMA_ADDR_LOW (Dev
, IoRequest
));
436 if (EFI_ERROR (Status
)) {
437 return EFI_DEVICE_ERROR
;
446 IN MPT_SCSI_DEV
*Dev
,
455 // Timeouts are not supported for
456 // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() in this implementation.
459 Status
= In32 (Dev
, MPT_REG_ISTATUS
, &Istatus
);
460 if (EFI_ERROR (Status
)) {
467 if (Istatus
& MPT_IMASK_REPLY
) {
471 gBS
->Stall (Dev
->StallPerPollUsec
);
474 Status
= In32 (Dev
, MPT_REG_REP_Q
, Reply
);
475 if (EFI_ERROR (Status
)) {
480 // The driver is supposed to fetch replies until 0xffffffff is returned, which
481 // will reset the interrupt status. We put only one request, so we expect the
482 // next read reply to be the last.
484 Status
= In32 (Dev
, MPT_REG_REP_Q
, &EmptyReply
);
485 if (EFI_ERROR (Status
) || (EmptyReply
!= MAX_UINT32
)) {
486 return EFI_DEVICE_ERROR
;
495 IN MPT_SCSI_DEV
*Dev
,
497 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
500 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
501 CopyMem (Packet
->InDataBuffer
, Dev
->Dma
->Data
, Packet
->InTransferLength
);
504 if (Reply
== Dev
->Dma
->IoRequest
.Data
.Header
.MessageContext
) {
506 // This is a turbo reply, everything is good
508 Packet
->SenseDataLength
= 0;
509 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
510 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
511 } else if ((Reply
& BIT31
) != 0) {
512 DEBUG ((DEBUG_INFO
, "%a: Full reply returned\n", __FUNCTION__
));
514 // When reply MSB is set, we got a full reply. Since we submitted only one
515 // reply frame, we know it's IoReply.
517 Dev
->IoReplyEnqueued
= FALSE
;
519 Packet
->TargetStatus
= Dev
->Dma
->IoReply
.Data
.ScsiStatus
;
521 // Make sure device only lowers SenseDataLength before copying sense
523 ASSERT (Dev
->Dma
->IoReply
.Data
.SenseCount
<= Packet
->SenseDataLength
);
524 Packet
->SenseDataLength
=
525 (UINT8
)MIN (Dev
->Dma
->IoReply
.Data
.SenseCount
, Packet
->SenseDataLength
);
526 CopyMem (Packet
->SenseData
, Dev
->Dma
->Sense
, Packet
->SenseDataLength
);
528 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
529 Packet
->InTransferLength
= Dev
->Dma
->IoReply
.Data
.TransferCount
;
531 Packet
->OutTransferLength
= Dev
->Dma
->IoReply
.Data
.TransferCount
;
534 switch (Dev
->Dma
->IoReply
.Data
.IocStatus
) {
535 case MPT_SCSI_IOCSTATUS_SUCCESS
:
536 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
538 case MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE
:
539 Packet
->HostAdapterStatus
=
540 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
;
542 case MPT_SCSI_IOCSTATUS_DATA_UNDERRUN
:
543 case MPT_SCSI_IOCSTATUS_DATA_OVERRUN
:
544 Packet
->HostAdapterStatus
=
545 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
548 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
549 return EFI_DEVICE_ERROR
;
552 DEBUG ((DEBUG_ERROR
, "%a: unexpected reply (%x)\n", __FUNCTION__
, Reply
));
553 return ReportHostAdapterError (Packet
);
560 // Ext SCSI Pass Thru
567 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
570 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
571 IN EFI_EVENT Event OPTIONAL
578 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
580 // We only use first byte of target identifer
582 Status
= MptScsiPopulateRequest (Dev
, *Target
, Lun
, Packet
);
583 if (EFI_ERROR (Status
)) {
585 // MptScsiPopulateRequest modified packet according to the error
590 Status
= MptScsiSendRequest (Dev
, Packet
);
591 if (EFI_ERROR (Status
)) {
592 return ReportHostAdapterError (Packet
);
595 Status
= MptScsiGetReply (Dev
, &Reply
);
596 if (EFI_ERROR (Status
)) {
597 return ReportHostAdapterError (Packet
);
600 return MptScsiHandleReply (Dev
, Reply
, Packet
);
605 IsTargetInitialized (
611 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
; ++Idx
) {
612 if (Target
[Idx
] != 0xFF) {
623 MptScsiGetNextTargetLun (
624 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
625 IN OUT UINT8
**Target
,
631 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
633 // Currently support only LUN 0, so hardcode it
635 if (!IsTargetInitialized (*Target
)) {
636 ZeroMem (*Target
, TARGET_MAX_BYTES
);
638 } else if ((**Target
> Dev
->MaxTarget
) || (*Lun
> 0)) {
639 return EFI_INVALID_PARAMETER
;
640 } else if (**Target
< Dev
->MaxTarget
) {
642 // This device interface support 256 targets only, so it's enough to
643 // increment the LSB of Target, as it will never overflow.
647 return EFI_NOT_FOUND
;
656 MptScsiGetNextTarget (
657 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
658 IN OUT UINT8
**Target
663 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
664 if (!IsTargetInitialized (*Target
)) {
665 ZeroMem (*Target
, TARGET_MAX_BYTES
);
666 } else if (**Target
> Dev
->MaxTarget
) {
667 return EFI_INVALID_PARAMETER
;
668 } else if (**Target
< Dev
->MaxTarget
) {
670 // This device interface support 256 targets only, so it's enough to
671 // increment the LSB of Target, as it will never overflow.
675 return EFI_NOT_FOUND
;
684 MptScsiBuildDevicePath (
685 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
688 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
692 SCSI_DEVICE_PATH
*ScsiDevicePath
;
694 if (DevicePath
== NULL
) {
695 return EFI_INVALID_PARAMETER
;
699 // This device support 256 targets only, so it's enough to dereference
700 // the LSB of Target.
702 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
703 if ((*Target
> Dev
->MaxTarget
) || (Lun
> 0)) {
704 return EFI_NOT_FOUND
;
707 ScsiDevicePath
= AllocateZeroPool (sizeof (*ScsiDevicePath
));
708 if (ScsiDevicePath
== NULL
) {
709 return EFI_OUT_OF_RESOURCES
;
712 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
713 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
714 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof (*ScsiDevicePath
);
715 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof (*ScsiDevicePath
) >> 8);
716 ScsiDevicePath
->Pun
= *Target
;
717 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
719 *DevicePath
= &ScsiDevicePath
->Header
;
726 MptScsiGetTargetLun (
727 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
728 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
734 SCSI_DEVICE_PATH
*ScsiDevicePath
;
736 if ((DevicePath
== NULL
) ||
737 (Target
== NULL
) || (*Target
== NULL
) || (Lun
== NULL
))
739 return EFI_INVALID_PARAMETER
;
742 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
743 (DevicePath
->SubType
!= MSG_SCSI_DP
))
745 return EFI_UNSUPPORTED
;
748 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
749 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
750 if ((ScsiDevicePath
->Pun
> Dev
->MaxTarget
) ||
751 (ScsiDevicePath
->Lun
> 0))
753 return EFI_NOT_FOUND
;
756 ZeroMem (*Target
, TARGET_MAX_BYTES
);
758 // This device support 256 targets only, so it's enough to set the LSB
761 **Target
= (UINT8
)ScsiDevicePath
->Pun
;
762 *Lun
= ScsiDevicePath
->Lun
;
770 MptScsiResetChannel (
771 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
774 return EFI_UNSUPPORTED
;
788 DEBUG ((DEBUG_VERBOSE
, "%a: Context=0x%p\n", __FUNCTION__
, Context
));
795 MptScsiResetTargetLun (
796 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
801 return EFI_UNSUPPORTED
;
811 MptScsiControllerSupported (
812 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
813 IN EFI_HANDLE ControllerHandle
,
814 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
818 EFI_PCI_IO_PROTOCOL
*PciIo
;
821 Status
= gBS
->OpenProtocol (
823 &gEfiPciIoProtocolGuid
,
825 This
->DriverBindingHandle
,
827 EFI_OPEN_PROTOCOL_BY_DRIVER
829 if (EFI_ERROR (Status
)) {
833 Status
= PciIo
->Pci
.Read (
837 sizeof (Pci
) / sizeof (UINT32
),
840 if (EFI_ERROR (Status
)) {
844 if ((Pci
.Hdr
.VendorId
== LSI_LOGIC_PCI_VENDOR_ID
) &&
845 ((Pci
.Hdr
.DeviceId
== LSI_53C1030_PCI_DEVICE_ID
) ||
846 (Pci
.Hdr
.DeviceId
== LSI_SAS1068_PCI_DEVICE_ID
) ||
847 (Pci
.Hdr
.DeviceId
== LSI_SAS1068E_PCI_DEVICE_ID
)))
849 Status
= EFI_SUCCESS
;
851 Status
= EFI_UNSUPPORTED
;
857 &gEfiPciIoProtocolGuid
,
858 This
->DriverBindingHandle
,
867 MptScsiControllerStart (
868 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
869 IN EFI_HANDLE ControllerHandle
,
870 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
878 Dev
= AllocateZeroPool (sizeof (*Dev
));
880 return EFI_OUT_OF_RESOURCES
;
883 Dev
->Signature
= MPT_SCSI_DEV_SIGNATURE
;
885 Dev
->MaxTarget
= PcdGet8 (PcdMptScsiMaxTargetLimit
);
886 Dev
->StallPerPollUsec
= PcdGet32 (PcdMptScsiStallPerPollUsec
);
888 Status
= gBS
->OpenProtocol (
890 &gEfiPciIoProtocolGuid
,
891 (VOID
**)&Dev
->PciIo
,
892 This
->DriverBindingHandle
,
894 EFI_OPEN_PROTOCOL_BY_DRIVER
896 if (EFI_ERROR (Status
)) {
900 Status
= Dev
->PciIo
->Attributes (
902 EfiPciIoAttributeOperationGet
,
904 &Dev
->OriginalPciAttributes
906 if (EFI_ERROR (Status
)) {
911 // Enable I/O Space & Bus-Mastering
913 Status
= Dev
->PciIo
->Attributes (
915 EfiPciIoAttributeOperationEnable
,
916 (EFI_PCI_IO_ATTRIBUTE_IO
|
917 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
920 if (EFI_ERROR (Status
)) {
925 // Signal device supports 64-bit DMA addresses
927 Status
= Dev
->PciIo
->Attributes (
929 EfiPciIoAttributeOperationEnable
,
930 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
933 if (EFI_ERROR (Status
)) {
935 // Warn user that device will only be using 32-bit DMA addresses.
937 // Note that this does not prevent the device/driver from working
938 // and therefore we only warn and continue as usual.
942 "%a: failed to enable 64-bit DMA addresses\n",
948 // Create buffers for data transfer
950 Pages
= EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
));
951 Status
= Dev
->PciIo
->AllocateBuffer (
957 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
959 if (EFI_ERROR (Status
)) {
960 goto RestoreAttributes
;
963 BytesMapped
= EFI_PAGES_TO_SIZE (Pages
);
964 Status
= Dev
->PciIo
->Map (
966 EfiPciIoOperationBusMasterCommonBuffer
,
972 if (EFI_ERROR (Status
)) {
976 if (BytesMapped
!= EFI_PAGES_TO_SIZE (Pages
)) {
977 Status
= EFI_OUT_OF_RESOURCES
;
981 Status
= MptScsiInit (Dev
);
982 if (EFI_ERROR (Status
)) {
986 Status
= gBS
->CreateEvent (
987 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
993 if (EFI_ERROR (Status
)) {
998 // Host adapter channel, doesn't exist
1000 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
1001 Dev
->PassThruMode
.Attributes
=
1002 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
1003 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
1005 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
1006 Dev
->PassThru
.PassThru
= &MptScsiPassThru
;
1007 Dev
->PassThru
.GetNextTargetLun
= &MptScsiGetNextTargetLun
;
1008 Dev
->PassThru
.BuildDevicePath
= &MptScsiBuildDevicePath
;
1009 Dev
->PassThru
.GetTargetLun
= &MptScsiGetTargetLun
;
1010 Dev
->PassThru
.ResetChannel
= &MptScsiResetChannel
;
1011 Dev
->PassThru
.ResetTargetLun
= &MptScsiResetTargetLun
;
1012 Dev
->PassThru
.GetNextTarget
= &MptScsiGetNextTarget
;
1014 Status
= gBS
->InstallProtocolInterface (
1016 &gEfiExtScsiPassThruProtocolGuid
,
1017 EFI_NATIVE_INTERFACE
,
1020 if (EFI_ERROR (Status
)) {
1027 gBS
->CloseEvent (Dev
->ExitBoot
);
1039 Dev
->PciIo
->FreeBuffer (
1046 Dev
->PciIo
->Attributes (
1048 EfiPciIoAttributeOperationSet
,
1049 Dev
->OriginalPciAttributes
,
1054 gBS
->CloseProtocol (
1056 &gEfiPciIoProtocolGuid
,
1057 This
->DriverBindingHandle
,
1070 MptScsiControllerStop (
1071 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1072 IN EFI_HANDLE ControllerHandle
,
1073 IN UINTN NumberOfChildren
,
1074 IN EFI_HANDLE
*ChildHandleBuffer
1078 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
1081 Status
= gBS
->OpenProtocol (
1083 &gEfiExtScsiPassThruProtocolGuid
,
1085 This
->DriverBindingHandle
,
1087 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
1089 if (EFI_ERROR (Status
)) {
1093 Dev
= MPT_SCSI_FROM_PASS_THRU (PassThru
);
1095 Status
= gBS
->UninstallProtocolInterface (
1097 &gEfiExtScsiPassThruProtocolGuid
,
1100 if (EFI_ERROR (Status
)) {
1104 gBS
->CloseEvent (Dev
->ExitBoot
);
1113 Dev
->PciIo
->FreeBuffer (
1115 EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
)),
1119 Dev
->PciIo
->Attributes (
1121 EfiPciIoAttributeOperationSet
,
1122 Dev
->OriginalPciAttributes
,
1126 gBS
->CloseProtocol (
1128 &gEfiPciIoProtocolGuid
,
1129 This
->DriverBindingHandle
,
1139 EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding
= {
1140 &MptScsiControllerSupported
,
1141 &MptScsiControllerStart
,
1142 &MptScsiControllerStop
,
1143 MPT_SCSI_BINDING_VERSION
,
1144 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
1145 NULL
, // DriverBindingHandle, filled as well
1153 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1154 { "eng;en", L
"LSI Fusion MPT SCSI Driver" },
1159 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1163 MptScsiGetDriverName (
1164 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1166 OUT CHAR16
**DriverName
1169 return LookupUnicodeString2 (
1171 This
->SupportedLanguages
,
1174 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1180 MptScsiGetDeviceName (
1181 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1182 IN EFI_HANDLE DeviceHandle
,
1183 IN EFI_HANDLE ChildHandle
,
1185 OUT CHAR16
**ControllerName
1188 return EFI_UNSUPPORTED
;
1192 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1193 &MptScsiGetDriverName
,
1194 &MptScsiGetDeviceName
,
1195 "eng" // SupportedLanguages, ISO 639-2 language codes
1199 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1200 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
)&MptScsiGetDriverName
,
1201 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
)&MptScsiGetDeviceName
,
1202 "en" // SupportedLanguages, RFC 4646 language codes
1212 IN EFI_HANDLE ImageHandle
,
1213 IN EFI_SYSTEM_TABLE
*SystemTable
1216 return EfiLibInstallDriverBindingComponentName2 (
1219 &mMptScsiDriverBinding
,
1220 ImageHandle
, // The handle to install onto