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
;
43 #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
44 CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
54 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
57 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
58 IN EFI_EVENT Event OPTIONAL
61 return EFI_UNSUPPORTED
;
72 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
; ++Idx
) {
73 if (Target
[Idx
] != 0xFF) {
83 MptScsiGetNextTargetLun (
84 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
85 IN OUT UINT8
**Target
,
91 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
93 // Currently support only LUN 0, so hardcode it
95 if (!IsTargetInitialized (*Target
)) {
96 ZeroMem (*Target
, TARGET_MAX_BYTES
);
98 } else if (**Target
> Dev
->MaxTarget
|| *Lun
> 0) {
99 return EFI_INVALID_PARAMETER
;
100 } else if (**Target
< Dev
->MaxTarget
) {
102 // This device interface support 256 targets only, so it's enough to
103 // increment the LSB of Target, as it will never overflow.
107 return EFI_NOT_FOUND
;
116 MptScsiGetNextTarget (
117 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
118 IN OUT UINT8
**Target
123 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
124 if (!IsTargetInitialized (*Target
)) {
125 ZeroMem (*Target
, TARGET_MAX_BYTES
);
126 } else if (**Target
> Dev
->MaxTarget
) {
127 return EFI_INVALID_PARAMETER
;
128 } else if (**Target
< Dev
->MaxTarget
) {
130 // This device interface support 256 targets only, so it's enough to
131 // increment the LSB of Target, as it will never overflow.
135 return EFI_NOT_FOUND
;
144 MptScsiBuildDevicePath (
145 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
148 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
152 SCSI_DEVICE_PATH
*ScsiDevicePath
;
154 if (DevicePath
== NULL
) {
155 return EFI_INVALID_PARAMETER
;
159 // This device support 256 targets only, so it's enough to dereference
160 // the LSB of Target.
162 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
163 if (*Target
> Dev
->MaxTarget
|| Lun
> 0) {
164 return EFI_NOT_FOUND
;
167 ScsiDevicePath
= AllocateZeroPool (sizeof (*ScsiDevicePath
));
168 if (ScsiDevicePath
== NULL
) {
169 return EFI_OUT_OF_RESOURCES
;
172 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
173 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
174 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof (*ScsiDevicePath
);
175 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof (*ScsiDevicePath
) >> 8);
176 ScsiDevicePath
->Pun
= *Target
;
177 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
179 *DevicePath
= &ScsiDevicePath
->Header
;
186 MptScsiGetTargetLun (
187 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
188 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
194 SCSI_DEVICE_PATH
*ScsiDevicePath
;
196 if (DevicePath
== NULL
||
197 Target
== NULL
|| *Target
== NULL
|| Lun
== NULL
) {
198 return EFI_INVALID_PARAMETER
;
201 if (DevicePath
->Type
!= MESSAGING_DEVICE_PATH
||
202 DevicePath
->SubType
!= MSG_SCSI_DP
) {
203 return EFI_UNSUPPORTED
;
206 Dev
= MPT_SCSI_FROM_PASS_THRU (This
);
207 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
208 if (ScsiDevicePath
->Pun
> Dev
->MaxTarget
||
209 ScsiDevicePath
->Lun
> 0) {
210 return EFI_NOT_FOUND
;
213 ZeroMem (*Target
, TARGET_MAX_BYTES
);
215 // This device support 256 targets only, so it's enough to set the LSB
218 **Target
= (UINT8
)ScsiDevicePath
->Pun
;
219 *Lun
= ScsiDevicePath
->Lun
;
227 MptScsiResetChannel (
228 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
231 return EFI_UNSUPPORTED
;
237 MptScsiResetTargetLun (
238 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
243 return EFI_UNSUPPORTED
;
253 MptScsiControllerSupported (
254 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
255 IN EFI_HANDLE ControllerHandle
,
256 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
260 EFI_PCI_IO_PROTOCOL
*PciIo
;
263 Status
= gBS
->OpenProtocol (
265 &gEfiPciIoProtocolGuid
,
267 This
->DriverBindingHandle
,
269 EFI_OPEN_PROTOCOL_BY_DRIVER
271 if (EFI_ERROR (Status
)) {
275 Status
= PciIo
->Pci
.Read (
279 sizeof (Pci
) / sizeof (UINT32
),
282 if (EFI_ERROR (Status
)) {
286 if (Pci
.Hdr
.VendorId
== LSI_LOGIC_PCI_VENDOR_ID
&&
287 (Pci
.Hdr
.DeviceId
== LSI_53C1030_PCI_DEVICE_ID
||
288 Pci
.Hdr
.DeviceId
== LSI_SAS1068_PCI_DEVICE_ID
||
289 Pci
.Hdr
.DeviceId
== LSI_SAS1068E_PCI_DEVICE_ID
)) {
290 Status
= EFI_SUCCESS
;
292 Status
= EFI_UNSUPPORTED
;
298 &gEfiPciIoProtocolGuid
,
299 This
->DriverBindingHandle
,
308 MptScsiControllerStart (
309 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
310 IN EFI_HANDLE ControllerHandle
,
311 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
317 Dev
= AllocateZeroPool (sizeof (*Dev
));
319 return EFI_OUT_OF_RESOURCES
;
322 Dev
->Signature
= MPT_SCSI_DEV_SIGNATURE
;
324 Dev
->MaxTarget
= PcdGet8 (PcdMptScsiMaxTargetLimit
);
326 Status
= gBS
->OpenProtocol (
328 &gEfiPciIoProtocolGuid
,
329 (VOID
**)&Dev
->PciIo
,
330 This
->DriverBindingHandle
,
332 EFI_OPEN_PROTOCOL_BY_DRIVER
334 if (EFI_ERROR (Status
)) {
339 // Host adapter channel, doesn't exist
341 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
342 Dev
->PassThruMode
.Attributes
=
343 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
344 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
346 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
347 Dev
->PassThru
.PassThru
= &MptScsiPassThru
;
348 Dev
->PassThru
.GetNextTargetLun
= &MptScsiGetNextTargetLun
;
349 Dev
->PassThru
.BuildDevicePath
= &MptScsiBuildDevicePath
;
350 Dev
->PassThru
.GetTargetLun
= &MptScsiGetTargetLun
;
351 Dev
->PassThru
.ResetChannel
= &MptScsiResetChannel
;
352 Dev
->PassThru
.ResetTargetLun
= &MptScsiResetTargetLun
;
353 Dev
->PassThru
.GetNextTarget
= &MptScsiGetNextTarget
;
355 Status
= gBS
->InstallProtocolInterface (
357 &gEfiExtScsiPassThruProtocolGuid
,
358 EFI_NATIVE_INTERFACE
,
361 if (EFI_ERROR (Status
)) {
370 &gEfiPciIoProtocolGuid
,
371 This
->DriverBindingHandle
,
384 MptScsiControllerStop (
385 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
386 IN EFI_HANDLE ControllerHandle
,
387 IN UINTN NumberOfChildren
,
388 IN EFI_HANDLE
*ChildHandleBuffer
392 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
395 Status
= gBS
->OpenProtocol (
397 &gEfiExtScsiPassThruProtocolGuid
,
399 This
->DriverBindingHandle
,
401 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
403 if (EFI_ERROR (Status
)) {
407 Dev
= MPT_SCSI_FROM_PASS_THRU (PassThru
);
409 Status
= gBS
->UninstallProtocolInterface (
411 &gEfiExtScsiPassThruProtocolGuid
,
414 if (EFI_ERROR (Status
)) {
420 &gEfiPciIoProtocolGuid
,
421 This
->DriverBindingHandle
,
431 EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding
= {
432 &MptScsiControllerSupported
,
433 &MptScsiControllerStart
,
434 &MptScsiControllerStop
,
435 MPT_SCSI_BINDING_VERSION
,
436 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
437 NULL
, // DriverBindingHandle, filled as well
445 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
446 { "eng;en", L
"LSI Fusion MPT SCSI Driver" },
451 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
455 MptScsiGetDriverName (
456 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
458 OUT CHAR16
**DriverName
461 return LookupUnicodeString2 (
463 This
->SupportedLanguages
,
466 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
472 MptScsiGetDeviceName (
473 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
474 IN EFI_HANDLE DeviceHandle
,
475 IN EFI_HANDLE ChildHandle
,
477 OUT CHAR16
**ControllerName
480 return EFI_UNSUPPORTED
;
484 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
485 &MptScsiGetDriverName
,
486 &MptScsiGetDeviceName
,
487 "eng" // SupportedLanguages, ISO 639-2 language codes
491 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
492 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &MptScsiGetDriverName
,
493 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &MptScsiGetDeviceName
,
494 "en" // SupportedLanguages, RFC 4646 language codes
504 IN EFI_HANDLE ImageHandle
,
505 IN EFI_SYSTEM_TABLE
*SystemTable
508 return EfiLibInstallDriverBindingComponentName2 (
511 &mMptScsiDriverBinding
,
512 ImageHandle
, // The handle to install onto