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/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/UefiLib.h>
20 #include <Protocol/PciIo.h>
21 #include <Protocol/ScsiPassThruExt.h>
22 #include <Uefi/UefiSpec.h>
25 // Higher versions will be used before lower, 0x10-0xffffffef is the version
26 // range for IVH (Indie Hardware Vendors)
28 #define MPT_SCSI_BINDING_VERSION 0x10
34 #define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
37 EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru
;
38 EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode
;
40 EFI_PCI_IO_PROTOCOL
*PciIo
;
41 UINT64 OriginalPciAttributes
;
44 #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
45 CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
55 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
58 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
59 IN EFI_EVENT Event OPTIONAL
62 return EFI_UNSUPPORTED
;
73 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
; ++Idx
) {
74 if (Target
[Idx
] != 0xFF) {
84 MptScsiGetNextTargetLun (
85 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
86 IN OUT UINT8
**Target
,
92 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
94 // Currently support only LUN 0, so hardcode it
96 if (!IsTargetInitialized (*Target
)) {
97 ZeroMem (*Target
, TARGET_MAX_BYTES
);
99 } else if (**Target
> Dev
->MaxTarget
|| *Lun
> 0) {
100 return EFI_INVALID_PARAMETER
;
101 } else if (**Target
< Dev
->MaxTarget
) {
103 // This device interface support 256 targets only, so it's enough to
104 // increment the LSB of Target, as it will never overflow.
108 return EFI_NOT_FOUND
;
117 MptScsiGetNextTarget (
118 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
119 IN OUT UINT8
**Target
124 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
125 if (!IsTargetInitialized (*Target
)) {
126 ZeroMem (*Target
, TARGET_MAX_BYTES
);
127 } else if (**Target
> Dev
->MaxTarget
) {
128 return EFI_INVALID_PARAMETER
;
129 } else if (**Target
< Dev
->MaxTarget
) {
131 // This device interface support 256 targets only, so it's enough to
132 // increment the LSB of Target, as it will never overflow.
136 return EFI_NOT_FOUND
;
145 MptScsiBuildDevicePath (
146 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
149 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
153 SCSI_DEVICE_PATH
*ScsiDevicePath
;
155 if (DevicePath
== NULL
) {
156 return EFI_INVALID_PARAMETER
;
160 // This device support 256 targets only, so it's enough to dereference
161 // the LSB of Target.
163 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
164 if (*Target
> Dev
->MaxTarget
|| Lun
> 0) {
165 return EFI_NOT_FOUND
;
168 ScsiDevicePath
= AllocateZeroPool (sizeof (*ScsiDevicePath
));
169 if (ScsiDevicePath
== NULL
) {
170 return EFI_OUT_OF_RESOURCES
;
173 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
174 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
175 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof (*ScsiDevicePath
);
176 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof (*ScsiDevicePath
) >> 8);
177 ScsiDevicePath
->Pun
= *Target
;
178 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
180 *DevicePath
= &ScsiDevicePath
->Header
;
187 MptScsiGetTargetLun (
188 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
189 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
195 SCSI_DEVICE_PATH
*ScsiDevicePath
;
197 if (DevicePath
== NULL
||
198 Target
== NULL
|| *Target
== NULL
|| Lun
== NULL
) {
199 return EFI_INVALID_PARAMETER
;
202 if (DevicePath
->Type
!= MESSAGING_DEVICE_PATH
||
203 DevicePath
->SubType
!= MSG_SCSI_DP
) {
204 return EFI_UNSUPPORTED
;
207 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
208 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
209 if (ScsiDevicePath
->Pun
> Dev
->MaxTarget
||
210 ScsiDevicePath
->Lun
> 0) {
211 return EFI_NOT_FOUND
;
214 ZeroMem (*Target
, TARGET_MAX_BYTES
);
216 // This device support 256 targets only, so it's enough to set the LSB
219 **Target
= (UINT8
)ScsiDevicePath
->Pun
;
220 *Lun
= ScsiDevicePath
->Lun
;
228 MptScsiResetChannel (
229 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
232 return EFI_UNSUPPORTED
;
238 MptScsiResetTargetLun (
239 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
244 return EFI_UNSUPPORTED
;
254 MptScsiControllerSupported (
255 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
256 IN EFI_HANDLE ControllerHandle
,
257 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
261 EFI_PCI_IO_PROTOCOL
*PciIo
;
264 Status
= gBS
->OpenProtocol (
266 &gEfiPciIoProtocolGuid
,
268 This
->DriverBindingHandle
,
270 EFI_OPEN_PROTOCOL_BY_DRIVER
272 if (EFI_ERROR (Status
)) {
276 Status
= PciIo
->Pci
.Read (
280 sizeof (Pci
) / sizeof (UINT32
),
283 if (EFI_ERROR (Status
)) {
287 if (Pci
.Hdr
.VendorId
== LSI_LOGIC_PCI_VENDOR_ID
&&
288 (Pci
.Hdr
.DeviceId
== LSI_53C1030_PCI_DEVICE_ID
||
289 Pci
.Hdr
.DeviceId
== LSI_SAS1068_PCI_DEVICE_ID
||
290 Pci
.Hdr
.DeviceId
== LSI_SAS1068E_PCI_DEVICE_ID
)) {
291 Status
= EFI_SUCCESS
;
293 Status
= EFI_UNSUPPORTED
;
299 &gEfiPciIoProtocolGuid
,
300 This
->DriverBindingHandle
,
309 MptScsiControllerStart (
310 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
311 IN EFI_HANDLE ControllerHandle
,
312 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
318 Dev
= AllocateZeroPool (sizeof (*Dev
));
320 return EFI_OUT_OF_RESOURCES
;
323 Dev
->Signature
= MPT_SCSI_DEV_SIGNATURE
;
325 Dev
->MaxTarget
= PcdGet8 (PcdMptScsiMaxTargetLimit
);
327 Status
= gBS
->OpenProtocol (
329 &gEfiPciIoProtocolGuid
,
330 (VOID
**)&Dev
->PciIo
,
331 This
->DriverBindingHandle
,
333 EFI_OPEN_PROTOCOL_BY_DRIVER
335 if (EFI_ERROR (Status
)) {
339 Status
= Dev
->PciIo
->Attributes (
341 EfiPciIoAttributeOperationGet
,
343 &Dev
->OriginalPciAttributes
345 if (EFI_ERROR (Status
)) {
350 // Enable I/O Space & Bus-Mastering
352 Status
= Dev
->PciIo
->Attributes (
354 EfiPciIoAttributeOperationEnable
,
355 (EFI_PCI_IO_ATTRIBUTE_IO
|
356 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
359 if (EFI_ERROR (Status
)) {
364 // Signal device supports 64-bit DMA addresses
366 Status
= Dev
->PciIo
->Attributes (
368 EfiPciIoAttributeOperationEnable
,
369 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
372 if (EFI_ERROR (Status
)) {
374 // Warn user that device will only be using 32-bit DMA addresses.
376 // Note that this does not prevent the device/driver from working
377 // and therefore we only warn and continue as usual.
381 "%a: failed to enable 64-bit DMA addresses\n",
387 // Host adapter channel, doesn't exist
389 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
390 Dev
->PassThruMode
.Attributes
=
391 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
392 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
394 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
395 Dev
->PassThru
.PassThru
= &MptScsiPassThru
;
396 Dev
->PassThru
.GetNextTargetLun
= &MptScsiGetNextTargetLun
;
397 Dev
->PassThru
.BuildDevicePath
= &MptScsiBuildDevicePath
;
398 Dev
->PassThru
.GetTargetLun
= &MptScsiGetTargetLun
;
399 Dev
->PassThru
.ResetChannel
= &MptScsiResetChannel
;
400 Dev
->PassThru
.ResetTargetLun
= &MptScsiResetTargetLun
;
401 Dev
->PassThru
.GetNextTarget
= &MptScsiGetNextTarget
;
403 Status
= gBS
->InstallProtocolInterface (
405 &gEfiExtScsiPassThruProtocolGuid
,
406 EFI_NATIVE_INTERFACE
,
409 if (EFI_ERROR (Status
)) {
410 goto RestoreAttributes
;
416 Dev
->PciIo
->Attributes (
418 EfiPciIoAttributeOperationSet
,
419 Dev
->OriginalPciAttributes
,
426 &gEfiPciIoProtocolGuid
,
427 This
->DriverBindingHandle
,
440 MptScsiControllerStop (
441 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
442 IN EFI_HANDLE ControllerHandle
,
443 IN UINTN NumberOfChildren
,
444 IN EFI_HANDLE
*ChildHandleBuffer
448 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
451 Status
= gBS
->OpenProtocol (
453 &gEfiExtScsiPassThruProtocolGuid
,
455 This
->DriverBindingHandle
,
457 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
459 if (EFI_ERROR (Status
)) {
463 Dev
= MPT_SCSI_FROM_PASS_THRU (PassThru
);
465 Status
= gBS
->UninstallProtocolInterface (
467 &gEfiExtScsiPassThruProtocolGuid
,
470 if (EFI_ERROR (Status
)) {
474 Dev
->PciIo
->Attributes (
476 EfiPciIoAttributeOperationSet
,
477 Dev
->OriginalPciAttributes
,
483 &gEfiPciIoProtocolGuid
,
484 This
->DriverBindingHandle
,
494 EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding
= {
495 &MptScsiControllerSupported
,
496 &MptScsiControllerStart
,
497 &MptScsiControllerStop
,
498 MPT_SCSI_BINDING_VERSION
,
499 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
500 NULL
, // DriverBindingHandle, filled as well
508 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
509 { "eng;en", L
"LSI Fusion MPT SCSI Driver" },
514 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
518 MptScsiGetDriverName (
519 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
521 OUT CHAR16
**DriverName
524 return LookupUnicodeString2 (
526 This
->SupportedLanguages
,
529 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
535 MptScsiGetDeviceName (
536 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
537 IN EFI_HANDLE DeviceHandle
,
538 IN EFI_HANDLE ChildHandle
,
540 OUT CHAR16
**ControllerName
543 return EFI_UNSUPPORTED
;
547 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
548 &MptScsiGetDriverName
,
549 &MptScsiGetDeviceName
,
550 "eng" // SupportedLanguages, ISO 639-2 language codes
554 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
555 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &MptScsiGetDriverName
,
556 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &MptScsiGetDeviceName
,
557 "en" // SupportedLanguages, RFC 4646 language codes
567 IN EFI_HANDLE ImageHandle
,
568 IN EFI_SYSTEM_TABLE
*SystemTable
571 return EfiLibInstallDriverBindingComponentName2 (
574 &mMptScsiDriverBinding
,
575 ImageHandle
, // The handle to install onto