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
)) {
154 Status
= Out32 (Dev
, MPT_REG_IMASK
, MPT_IMASK_DOORBELL
| MPT_IMASK_REPLY
);
155 if (EFI_ERROR (Status
)) {
159 // Clear interrupt status
161 Status
= Out32 (Dev
, MPT_REG_ISTATUS
, 0);
162 if (EFI_ERROR (Status
)) {
177 MPT_IO_CONTROLLER_INIT_REQUEST Data
;
180 MPT_IO_CONTROLLER_INIT_REQUEST
*Req
;
181 MPT_IO_CONTROLLER_INIT_REPLY Reply
;
185 Req
= &AlignedReq
.Data
;
187 Status
= MptScsiReset (Dev
);
188 if (EFI_ERROR (Status
)) {
192 ZeroMem (Req
, sizeof (*Req
));
193 ZeroMem (&Reply
, sizeof (Reply
));
194 Req
->WhoInit
= MPT_IOC_WHOINIT_ROM_BIOS
;
195 Req
->Function
= MPT_MESSAGE_HDR_FUNCTION_IOC_INIT
;
197 FixedPcdGet8 (PcdMptScsiMaxTargetLimit
) < 255,
198 "Req supports 255 targets only (max target is 254)"
200 Req
->MaxDevices
= Dev
->MaxTarget
+ 1;
202 Req
->ReplyFrameSize
= sizeof Dev
->Dma
->IoReply
.Data
;
203 Req
->HostMfaHighAddr
= MPT_SCSI_DMA_ADDR_HIGH (Dev
, IoRequest
);
204 Req
->SenseBufferHighAddr
= MPT_SCSI_DMA_ADDR_HIGH (Dev
, Sense
);
207 // Send controller init through doorbell
210 sizeof (*Req
) % sizeof (UINT32
) == 0,
211 "Req must be multiple of UINT32"
214 sizeof (*Req
) / sizeof (UINT32
) <= MAX_UINT8
,
215 "Req must fit in MAX_UINT8 Dwords"
217 Status
= MptDoorbell (
219 MPT_DOORBELL_HANDSHAKE
,
220 (UINT8
)(sizeof (*Req
) / sizeof (UINT32
))
222 if (EFI_ERROR (Status
)) {
225 Status
= Dev
->PciIo
->Io
.Write (
227 EfiPciIoWidthFifoUint32
,
230 sizeof (*Req
) / sizeof (UINT32
),
233 if (EFI_ERROR (Status
)) {
238 // Read reply through doorbell
239 // Each 32bit (Dword) read produces 16bit (Word) of data
241 // The reply is read back to complete the doorbell function but it
242 // isn't useful because it doesn't contain relevant data or status
246 sizeof (Reply
) % sizeof (UINT16
) == 0,
247 "Reply must be multiple of UINT16"
249 ReplyBytes
= (UINT8
*)&Reply
;
250 while (ReplyBytes
!= (UINT8
*)(&Reply
+ 1)) {
251 Status
= In32 (Dev
, MPT_REG_DOORBELL
, &ReplyWord
);
252 if (EFI_ERROR (Status
)) {
255 CopyMem (ReplyBytes
, &ReplyWord
, sizeof (UINT16
));
256 ReplyBytes
+= sizeof (UINT16
);
260 // Clear interrupts generated by doorbell reply
262 Status
= Out32 (Dev
, MPT_REG_ISTATUS
, 0);
263 if (EFI_ERROR (Status
)) {
272 ReportHostAdapterError (
273 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
276 DEBUG ((DEBUG_ERROR
, "%a: fatal error in scsi request\n", __FUNCTION__
));
277 Packet
->InTransferLength
= 0;
278 Packet
->OutTransferLength
= 0;
279 Packet
->SenseDataLength
= 0;
280 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
281 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED
;
282 return EFI_DEVICE_ERROR
;
287 ReportHostAdapterOverrunError (
288 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
291 Packet
->SenseDataLength
= 0;
292 Packet
->HostAdapterStatus
=
293 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
294 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
295 return EFI_BAD_BUFFER_SIZE
;
300 MptScsiPopulateRequest (
301 IN MPT_SCSI_DEV
*Dev
,
304 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
307 MPT_SCSI_REQUEST_WITH_SG
*Request
;
309 Request
= &Dev
->Dma
->IoRequest
.Data
;
311 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
||
312 (Packet
->InTransferLength
> 0 && Packet
->OutTransferLength
> 0) ||
313 Packet
->CdbLength
> sizeof (Request
->Header
.Cdb
)) {
314 return EFI_UNSUPPORTED
;
317 if (Target
> Dev
->MaxTarget
|| Lun
> 0 ||
318 Packet
->DataDirection
> EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
||
320 // Trying to receive, but destination pointer is NULL, or contradicting
321 // transfer direction
323 (Packet
->InTransferLength
> 0 &&
324 (Packet
->InDataBuffer
== NULL
||
325 Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_WRITE
330 // Trying to send, but source pointer is NULL, or contradicting transfer
333 (Packet
->OutTransferLength
> 0 &&
334 (Packet
->OutDataBuffer
== NULL
||
335 Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
339 return EFI_INVALID_PARAMETER
;
342 if (Packet
->InTransferLength
> sizeof (Dev
->Dma
->Data
)) {
343 Packet
->InTransferLength
= sizeof (Dev
->Dma
->Data
);
344 return ReportHostAdapterOverrunError (Packet
);
346 if (Packet
->OutTransferLength
> sizeof (Dev
->Dma
->Data
)) {
347 Packet
->OutTransferLength
= sizeof (Dev
->Dma
->Data
);
348 return ReportHostAdapterOverrunError (Packet
);
351 ZeroMem (Request
, sizeof (*Request
));
352 Request
->Header
.TargetId
= Target
;
354 // Only LUN 0 is currently supported, hence the cast is safe
356 Request
->Header
.Lun
[1] = (UINT8
)Lun
;
357 Request
->Header
.Function
= MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST
;
358 Request
->Header
.MessageContext
= 1; // We handle one request at a time
360 Request
->Header
.CdbLength
= Packet
->CdbLength
;
361 CopyMem (Request
->Header
.Cdb
, Packet
->Cdb
, Packet
->CdbLength
);
364 // SenseDataLength is UINT8, Sense[] is MAX_UINT8, so we can't overflow
366 ZeroMem (Dev
->Dma
->Sense
, Packet
->SenseDataLength
);
367 Request
->Header
.SenseBufferLength
= Packet
->SenseDataLength
;
368 Request
->Header
.SenseBufferLowAddress
= MPT_SCSI_DMA_ADDR_LOW (Dev
, Sense
);
370 Request
->Sg
.EndOfList
= 1;
371 Request
->Sg
.EndOfBuffer
= 1;
372 Request
->Sg
.LastElement
= 1;
373 Request
->Sg
.ElementType
= MPT_SG_ENTRY_TYPE_SIMPLE
;
374 Request
->Sg
.Is64BitAddress
= 1;
375 Request
->Sg
.DataBufferAddress
= MPT_SCSI_DMA_ADDR (Dev
, Data
);
378 // "MPT_SG_ENTRY_SIMPLE.Length" is a 24-bit quantity.
381 sizeof (Dev
->Dma
->Data
) < SIZE_16MB
,
382 "MPT_SCSI_DMA_BUFFER.Data must be smaller than 16MB"
385 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
386 Request
->Header
.DataLength
= Packet
->InTransferLength
;
387 Request
->Sg
.Length
= Packet
->InTransferLength
;
388 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ
;
390 Request
->Header
.DataLength
= Packet
->OutTransferLength
;
391 Request
->Sg
.Length
= Packet
->OutTransferLength
;
392 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE
;
394 CopyMem (Dev
->Dma
->Data
, Packet
->OutDataBuffer
, Packet
->OutTransferLength
);
395 Request
->Sg
.BufferContainsData
= 1;
398 if (Request
->Header
.DataLength
== 0) {
399 Request
->Header
.Control
= MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE
;
408 IN MPT_SCSI_DEV
*Dev
,
409 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
414 if (!Dev
->IoReplyEnqueued
) {
416 // Put one free reply frame on the reply queue, the hardware may use it to
417 // report an error to us.
419 Status
= Out32 (Dev
, MPT_REG_REP_Q
, MPT_SCSI_DMA_ADDR_LOW (Dev
, IoReply
));
420 if (EFI_ERROR (Status
)) {
421 return EFI_DEVICE_ERROR
;
423 Dev
->IoReplyEnqueued
= TRUE
;
426 Status
= Out32 (Dev
, MPT_REG_REQ_Q
, MPT_SCSI_DMA_ADDR_LOW (Dev
, IoRequest
));
427 if (EFI_ERROR (Status
)) {
428 return EFI_DEVICE_ERROR
;
437 IN MPT_SCSI_DEV
*Dev
,
446 // Timeouts are not supported for
447 // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() in this implementation.
450 Status
= In32 (Dev
, MPT_REG_ISTATUS
, &Istatus
);
451 if (EFI_ERROR (Status
)) {
458 if (Istatus
& MPT_IMASK_REPLY
) {
462 gBS
->Stall (Dev
->StallPerPollUsec
);
465 Status
= In32 (Dev
, MPT_REG_REP_Q
, Reply
);
466 if (EFI_ERROR (Status
)) {
471 // The driver is supposed to fetch replies until 0xffffffff is returned, which
472 // will reset the interrupt status. We put only one request, so we expect the
473 // next read reply to be the last.
475 Status
= In32 (Dev
, MPT_REG_REP_Q
, &EmptyReply
);
476 if (EFI_ERROR (Status
) || EmptyReply
!= MAX_UINT32
) {
477 return EFI_DEVICE_ERROR
;
486 IN MPT_SCSI_DEV
*Dev
,
488 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
491 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
492 CopyMem (Packet
->InDataBuffer
, Dev
->Dma
->Data
, Packet
->InTransferLength
);
495 if (Reply
== Dev
->Dma
->IoRequest
.Data
.Header
.MessageContext
) {
497 // This is a turbo reply, everything is good
499 Packet
->SenseDataLength
= 0;
500 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
501 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
503 } else if ((Reply
& BIT31
) != 0) {
504 DEBUG ((DEBUG_INFO
, "%a: Full reply returned\n", __FUNCTION__
));
506 // When reply MSB is set, we got a full reply. Since we submitted only one
507 // reply frame, we know it's IoReply.
509 Dev
->IoReplyEnqueued
= FALSE
;
511 Packet
->TargetStatus
= Dev
->Dma
->IoReply
.Data
.ScsiStatus
;
513 // Make sure device only lowers SenseDataLength before copying sense
515 ASSERT (Dev
->Dma
->IoReply
.Data
.SenseCount
<= Packet
->SenseDataLength
);
516 Packet
->SenseDataLength
=
517 (UINT8
)MIN (Dev
->Dma
->IoReply
.Data
.SenseCount
, Packet
->SenseDataLength
);
518 CopyMem (Packet
->SenseData
, Dev
->Dma
->Sense
, Packet
->SenseDataLength
);
520 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
521 Packet
->InTransferLength
= Dev
->Dma
->IoReply
.Data
.TransferCount
;
523 Packet
->OutTransferLength
= Dev
->Dma
->IoReply
.Data
.TransferCount
;
526 switch (Dev
->Dma
->IoReply
.Data
.IocStatus
) {
527 case MPT_SCSI_IOCSTATUS_SUCCESS
:
528 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
530 case MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE
:
531 Packet
->HostAdapterStatus
=
532 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
;
534 case MPT_SCSI_IOCSTATUS_DATA_UNDERRUN
:
535 case MPT_SCSI_IOCSTATUS_DATA_OVERRUN
:
536 Packet
->HostAdapterStatus
=
537 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
540 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
541 return EFI_DEVICE_ERROR
;
545 DEBUG ((DEBUG_ERROR
, "%a: unexpected reply (%x)\n", __FUNCTION__
, Reply
));
546 return ReportHostAdapterError (Packet
);
553 // Ext SCSI Pass Thru
560 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
563 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
564 IN EFI_EVENT Event OPTIONAL
571 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
573 // We only use first byte of target identifer
575 Status
= MptScsiPopulateRequest (Dev
, *Target
, Lun
, Packet
);
576 if (EFI_ERROR (Status
)) {
578 // MptScsiPopulateRequest modified packet according to the error
583 Status
= MptScsiSendRequest (Dev
, Packet
);
584 if (EFI_ERROR (Status
)) {
585 return ReportHostAdapterError (Packet
);
588 Status
= MptScsiGetReply (Dev
, &Reply
);
589 if (EFI_ERROR (Status
)) {
590 return ReportHostAdapterError (Packet
);
593 return MptScsiHandleReply (Dev
, Reply
, Packet
);
598 IsTargetInitialized (
604 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
; ++Idx
) {
605 if (Target
[Idx
] != 0xFF) {
615 MptScsiGetNextTargetLun (
616 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
617 IN OUT UINT8
**Target
,
623 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
625 // Currently support only LUN 0, so hardcode it
627 if (!IsTargetInitialized (*Target
)) {
628 ZeroMem (*Target
, TARGET_MAX_BYTES
);
630 } else if (**Target
> Dev
->MaxTarget
|| *Lun
> 0) {
631 return EFI_INVALID_PARAMETER
;
632 } else if (**Target
< Dev
->MaxTarget
) {
634 // This device interface support 256 targets only, so it's enough to
635 // increment the LSB of Target, as it will never overflow.
639 return EFI_NOT_FOUND
;
648 MptScsiGetNextTarget (
649 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
650 IN OUT UINT8
**Target
655 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
656 if (!IsTargetInitialized (*Target
)) {
657 ZeroMem (*Target
, TARGET_MAX_BYTES
);
658 } else if (**Target
> Dev
->MaxTarget
) {
659 return EFI_INVALID_PARAMETER
;
660 } else if (**Target
< Dev
->MaxTarget
) {
662 // This device interface support 256 targets only, so it's enough to
663 // increment the LSB of Target, as it will never overflow.
667 return EFI_NOT_FOUND
;
676 MptScsiBuildDevicePath (
677 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
680 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
684 SCSI_DEVICE_PATH
*ScsiDevicePath
;
686 if (DevicePath
== NULL
) {
687 return EFI_INVALID_PARAMETER
;
691 // This device support 256 targets only, so it's enough to dereference
692 // the LSB of Target.
694 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
695 if (*Target
> Dev
->MaxTarget
|| Lun
> 0) {
696 return EFI_NOT_FOUND
;
699 ScsiDevicePath
= AllocateZeroPool (sizeof (*ScsiDevicePath
));
700 if (ScsiDevicePath
== NULL
) {
701 return EFI_OUT_OF_RESOURCES
;
704 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
705 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
706 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof (*ScsiDevicePath
);
707 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof (*ScsiDevicePath
) >> 8);
708 ScsiDevicePath
->Pun
= *Target
;
709 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
711 *DevicePath
= &ScsiDevicePath
->Header
;
718 MptScsiGetTargetLun (
719 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
720 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
726 SCSI_DEVICE_PATH
*ScsiDevicePath
;
728 if (DevicePath
== NULL
||
729 Target
== NULL
|| *Target
== NULL
|| Lun
== NULL
) {
730 return EFI_INVALID_PARAMETER
;
733 if (DevicePath
->Type
!= MESSAGING_DEVICE_PATH
||
734 DevicePath
->SubType
!= MSG_SCSI_DP
) {
735 return EFI_UNSUPPORTED
;
738 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
739 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
740 if (ScsiDevicePath
->Pun
> Dev
->MaxTarget
||
741 ScsiDevicePath
->Lun
> 0) {
742 return EFI_NOT_FOUND
;
745 ZeroMem (*Target
, TARGET_MAX_BYTES
);
747 // This device support 256 targets only, so it's enough to set the LSB
750 **Target
= (UINT8
)ScsiDevicePath
->Pun
;
751 *Lun
= ScsiDevicePath
->Lun
;
759 MptScsiResetChannel (
760 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
763 return EFI_UNSUPPORTED
;
777 DEBUG ((DEBUG_VERBOSE
, "%a: Context=0x%p\n", __FUNCTION__
, Context
));
783 MptScsiResetTargetLun (
784 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
789 return EFI_UNSUPPORTED
;
799 MptScsiControllerSupported (
800 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
801 IN EFI_HANDLE ControllerHandle
,
802 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
806 EFI_PCI_IO_PROTOCOL
*PciIo
;
809 Status
= gBS
->OpenProtocol (
811 &gEfiPciIoProtocolGuid
,
813 This
->DriverBindingHandle
,
815 EFI_OPEN_PROTOCOL_BY_DRIVER
817 if (EFI_ERROR (Status
)) {
821 Status
= PciIo
->Pci
.Read (
825 sizeof (Pci
) / sizeof (UINT32
),
828 if (EFI_ERROR (Status
)) {
832 if (Pci
.Hdr
.VendorId
== LSI_LOGIC_PCI_VENDOR_ID
&&
833 (Pci
.Hdr
.DeviceId
== LSI_53C1030_PCI_DEVICE_ID
||
834 Pci
.Hdr
.DeviceId
== LSI_SAS1068_PCI_DEVICE_ID
||
835 Pci
.Hdr
.DeviceId
== LSI_SAS1068E_PCI_DEVICE_ID
)) {
836 Status
= EFI_SUCCESS
;
838 Status
= EFI_UNSUPPORTED
;
844 &gEfiPciIoProtocolGuid
,
845 This
->DriverBindingHandle
,
854 MptScsiControllerStart (
855 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
856 IN EFI_HANDLE ControllerHandle
,
857 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
865 Dev
= AllocateZeroPool (sizeof (*Dev
));
867 return EFI_OUT_OF_RESOURCES
;
870 Dev
->Signature
= MPT_SCSI_DEV_SIGNATURE
;
872 Dev
->MaxTarget
= PcdGet8 (PcdMptScsiMaxTargetLimit
);
873 Dev
->StallPerPollUsec
= PcdGet32 (PcdMptScsiStallPerPollUsec
);
875 Status
= gBS
->OpenProtocol (
877 &gEfiPciIoProtocolGuid
,
878 (VOID
**)&Dev
->PciIo
,
879 This
->DriverBindingHandle
,
881 EFI_OPEN_PROTOCOL_BY_DRIVER
883 if (EFI_ERROR (Status
)) {
887 Status
= Dev
->PciIo
->Attributes (
889 EfiPciIoAttributeOperationGet
,
891 &Dev
->OriginalPciAttributes
893 if (EFI_ERROR (Status
)) {
898 // Enable I/O Space & Bus-Mastering
900 Status
= Dev
->PciIo
->Attributes (
902 EfiPciIoAttributeOperationEnable
,
903 (EFI_PCI_IO_ATTRIBUTE_IO
|
904 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
907 if (EFI_ERROR (Status
)) {
912 // Signal device supports 64-bit DMA addresses
914 Status
= Dev
->PciIo
->Attributes (
916 EfiPciIoAttributeOperationEnable
,
917 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
920 if (EFI_ERROR (Status
)) {
922 // Warn user that device will only be using 32-bit DMA addresses.
924 // Note that this does not prevent the device/driver from working
925 // and therefore we only warn and continue as usual.
929 "%a: failed to enable 64-bit DMA addresses\n",
935 // Create buffers for data transfer
937 Pages
= EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
));
938 Status
= Dev
->PciIo
->AllocateBuffer (
944 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
946 if (EFI_ERROR (Status
)) {
947 goto RestoreAttributes
;
950 BytesMapped
= EFI_PAGES_TO_SIZE (Pages
);
951 Status
= Dev
->PciIo
->Map (
953 EfiPciIoOperationBusMasterCommonBuffer
,
959 if (EFI_ERROR (Status
)) {
963 if (BytesMapped
!= EFI_PAGES_TO_SIZE (Pages
)) {
964 Status
= EFI_OUT_OF_RESOURCES
;
968 Status
= MptScsiInit (Dev
);
969 if (EFI_ERROR (Status
)) {
973 Status
= gBS
->CreateEvent (
974 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
980 if (EFI_ERROR (Status
)) {
985 // Host adapter channel, doesn't exist
987 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
988 Dev
->PassThruMode
.Attributes
=
989 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
990 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
992 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
993 Dev
->PassThru
.PassThru
= &MptScsiPassThru
;
994 Dev
->PassThru
.GetNextTargetLun
= &MptScsiGetNextTargetLun
;
995 Dev
->PassThru
.BuildDevicePath
= &MptScsiBuildDevicePath
;
996 Dev
->PassThru
.GetTargetLun
= &MptScsiGetTargetLun
;
997 Dev
->PassThru
.ResetChannel
= &MptScsiResetChannel
;
998 Dev
->PassThru
.ResetTargetLun
= &MptScsiResetTargetLun
;
999 Dev
->PassThru
.GetNextTarget
= &MptScsiGetNextTarget
;
1001 Status
= gBS
->InstallProtocolInterface (
1003 &gEfiExtScsiPassThruProtocolGuid
,
1004 EFI_NATIVE_INTERFACE
,
1007 if (EFI_ERROR (Status
)) {
1014 gBS
->CloseEvent (Dev
->ExitBoot
);
1026 Dev
->PciIo
->FreeBuffer (
1033 Dev
->PciIo
->Attributes (
1035 EfiPciIoAttributeOperationSet
,
1036 Dev
->OriginalPciAttributes
,
1041 gBS
->CloseProtocol (
1043 &gEfiPciIoProtocolGuid
,
1044 This
->DriverBindingHandle
,
1057 MptScsiControllerStop (
1058 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1059 IN EFI_HANDLE ControllerHandle
,
1060 IN UINTN NumberOfChildren
,
1061 IN EFI_HANDLE
*ChildHandleBuffer
1065 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
1068 Status
= gBS
->OpenProtocol (
1070 &gEfiExtScsiPassThruProtocolGuid
,
1072 This
->DriverBindingHandle
,
1074 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
1076 if (EFI_ERROR (Status
)) {
1080 Dev
= MPT_SCSI_FROM_PASS_THRU (PassThru
);
1082 Status
= gBS
->UninstallProtocolInterface (
1084 &gEfiExtScsiPassThruProtocolGuid
,
1087 if (EFI_ERROR (Status
)) {
1091 gBS
->CloseEvent (Dev
->ExitBoot
);
1100 Dev
->PciIo
->FreeBuffer (
1102 EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
)),
1106 Dev
->PciIo
->Attributes (
1108 EfiPciIoAttributeOperationSet
,
1109 Dev
->OriginalPciAttributes
,
1113 gBS
->CloseProtocol (
1115 &gEfiPciIoProtocolGuid
,
1116 This
->DriverBindingHandle
,
1126 EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding
= {
1127 &MptScsiControllerSupported
,
1128 &MptScsiControllerStart
,
1129 &MptScsiControllerStop
,
1130 MPT_SCSI_BINDING_VERSION
,
1131 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
1132 NULL
, // DriverBindingHandle, filled as well
1140 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1141 { "eng;en", L
"LSI Fusion MPT SCSI Driver" },
1146 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1150 MptScsiGetDriverName (
1151 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1153 OUT CHAR16
**DriverName
1156 return LookupUnicodeString2 (
1158 This
->SupportedLanguages
,
1161 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1167 MptScsiGetDeviceName (
1168 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1169 IN EFI_HANDLE DeviceHandle
,
1170 IN EFI_HANDLE ChildHandle
,
1172 OUT CHAR16
**ControllerName
1175 return EFI_UNSUPPORTED
;
1179 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1180 &MptScsiGetDriverName
,
1181 &MptScsiGetDeviceName
,
1182 "eng" // SupportedLanguages, ISO 639-2 language codes
1186 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1187 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &MptScsiGetDriverName
,
1188 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &MptScsiGetDeviceName
,
1189 "en" // SupportedLanguages, RFC 4646 language codes
1199 IN EFI_HANDLE ImageHandle
,
1200 IN EFI_SYSTEM_TABLE
*SystemTable
1203 return EfiLibInstallDriverBindingComponentName2 (
1206 &mMptScsiDriverBinding
,
1207 ImageHandle
, // The handle to install onto