3 This driver produces Extended SCSI Pass Thru Protocol instances for
4 LSI 53C895A SCSI devices.
6 Copyright (C) 2020, SUSE LLC.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <IndustryStandard/LsiScsi.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>
29 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
30 // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
32 // - 14.1 SCSI Driver Model Overview,
33 // - 14.7 Extended SCSI Pass Thru Protocol.
39 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
42 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
43 IN EFI_EVENT Event OPTIONAL
46 return EFI_UNSUPPORTED
;
51 LsiScsiGetNextTargetLun (
52 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
53 IN OUT UINT8
**TargetPointer
,
63 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
65 Target
= *TargetPointer
;
68 // Search for first non-0xFF byte. If not found, return first target & LUN.
70 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
&& Target
[Idx
] == 0xFF; ++Idx
)
72 if (Idx
== TARGET_MAX_BYTES
) {
73 SetMem (Target
, TARGET_MAX_BYTES
, 0x00);
78 CopyMem (&LastTarget
, Target
, sizeof LastTarget
);
81 // increment (target, LUN) pair if valid on input
83 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
84 if (LastTarget
> Dev
->MaxTarget
|| *Lun
> Dev
->MaxLun
) {
85 return EFI_INVALID_PARAMETER
;
88 if (*Lun
< Dev
->MaxLun
) {
93 if (LastTarget
< Dev
->MaxTarget
) {
96 CopyMem (Target
, &LastTarget
, sizeof LastTarget
);
100 return EFI_NOT_FOUND
;
105 LsiScsiBuildDevicePath (
106 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
109 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
114 SCSI_DEVICE_PATH
*ScsiDevicePath
;
116 if (DevicePath
== NULL
) {
117 return EFI_INVALID_PARAMETER
;
120 CopyMem (&TargetValue
, Target
, sizeof TargetValue
);
121 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
122 if (TargetValue
> Dev
->MaxTarget
|| Lun
> Dev
->MaxLun
|| Lun
> 0xFFFF) {
123 return EFI_NOT_FOUND
;
126 ScsiDevicePath
= AllocatePool (sizeof *ScsiDevicePath
);
127 if (ScsiDevicePath
== NULL
) {
128 return EFI_OUT_OF_RESOURCES
;
131 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
132 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
133 ScsiDevicePath
->Header
.Length
[0] = (UINT8
) sizeof *ScsiDevicePath
;
134 ScsiDevicePath
->Header
.Length
[1] = (UINT8
) (sizeof *ScsiDevicePath
>> 8);
135 ScsiDevicePath
->Pun
= TargetValue
;
136 ScsiDevicePath
->Lun
= (UINT16
) Lun
;
138 *DevicePath
= &ScsiDevicePath
->Header
;
144 LsiScsiGetTargetLun (
145 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
146 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
147 OUT UINT8
**TargetPointer
,
151 SCSI_DEVICE_PATH
*ScsiDevicePath
;
155 if (DevicePath
== NULL
|| TargetPointer
== NULL
|| *TargetPointer
== NULL
||
157 return EFI_INVALID_PARAMETER
;
160 if (DevicePath
->Type
!= MESSAGING_DEVICE_PATH
||
161 DevicePath
->SubType
!= MSG_SCSI_DP
) {
162 return EFI_UNSUPPORTED
;
165 ScsiDevicePath
= (SCSI_DEVICE_PATH
*) DevicePath
;
166 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
167 if (ScsiDevicePath
->Pun
> Dev
->MaxTarget
||
168 ScsiDevicePath
->Lun
> Dev
->MaxLun
) {
169 return EFI_NOT_FOUND
;
172 Target
= *TargetPointer
;
173 ZeroMem (Target
, TARGET_MAX_BYTES
);
174 CopyMem (Target
, &ScsiDevicePath
->Pun
, sizeof ScsiDevicePath
->Pun
);
175 *Lun
= ScsiDevicePath
->Lun
;
182 LsiScsiResetChannel (
183 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
186 return EFI_UNSUPPORTED
;
191 LsiScsiResetTargetLun (
192 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
197 return EFI_UNSUPPORTED
;
202 LsiScsiGetNextTarget (
203 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
204 IN OUT UINT8
**TargetPointer
213 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
215 Target
= *TargetPointer
;
218 // Search for first non-0xFF byte. If not found, return first target.
220 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
&& Target
[Idx
] == 0xFF; ++Idx
)
222 if (Idx
== TARGET_MAX_BYTES
) {
223 SetMem (Target
, TARGET_MAX_BYTES
, 0x00);
227 CopyMem (&LastTarget
, Target
, sizeof LastTarget
);
230 // increment target if valid on input
232 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
233 if (LastTarget
> Dev
->MaxTarget
) {
234 return EFI_INVALID_PARAMETER
;
237 if (LastTarget
< Dev
->MaxTarget
) {
239 CopyMem (Target
, &LastTarget
, sizeof LastTarget
);
243 return EFI_NOT_FOUND
;
247 // Probe, start and stop functions of this driver, called by the DXE core for
250 // The following specifications document these interfaces:
251 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
252 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
257 LsiScsiControllerSupported (
258 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
259 IN EFI_HANDLE ControllerHandle
,
260 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
264 EFI_PCI_IO_PROTOCOL
*PciIo
;
267 Status
= gBS
->OpenProtocol (
269 &gEfiPciIoProtocolGuid
,
271 This
->DriverBindingHandle
,
273 EFI_OPEN_PROTOCOL_BY_DRIVER
275 if (EFI_ERROR (Status
)) {
279 Status
= PciIo
->Pci
.Read (
283 sizeof (Pci
) / sizeof (UINT32
),
286 if (EFI_ERROR (Status
)) {
290 if (Pci
.Hdr
.VendorId
== LSI_LOGIC_PCI_VENDOR_ID
&&
291 Pci
.Hdr
.DeviceId
== LSI_53C895A_PCI_DEVICE_ID
) {
292 Status
= EFI_SUCCESS
;
294 Status
= EFI_UNSUPPORTED
;
300 &gEfiPciIoProtocolGuid
,
301 This
->DriverBindingHandle
,
309 LsiScsiControllerStart (
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
= LSI_SCSI_DEV_SIGNATURE
;
326 FixedPcdGet8 (PcdLsiScsiMaxTargetLimit
) < 8,
327 "LSI 53C895A supports targets [0..7]"
330 FixedPcdGet8 (PcdLsiScsiMaxLunLimit
) < 128,
331 "LSI 53C895A supports LUNs [0..127]"
333 Dev
->MaxTarget
= PcdGet8 (PcdLsiScsiMaxTargetLimit
);
334 Dev
->MaxLun
= PcdGet8 (PcdLsiScsiMaxLunLimit
);
337 // Host adapter channel, doesn't exist
339 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
340 Dev
->PassThruMode
.Attributes
=
341 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
342 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
344 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
345 Dev
->PassThru
.PassThru
= &LsiScsiPassThru
;
346 Dev
->PassThru
.GetNextTargetLun
= &LsiScsiGetNextTargetLun
;
347 Dev
->PassThru
.BuildDevicePath
= &LsiScsiBuildDevicePath
;
348 Dev
->PassThru
.GetTargetLun
= &LsiScsiGetTargetLun
;
349 Dev
->PassThru
.ResetChannel
= &LsiScsiResetChannel
;
350 Dev
->PassThru
.ResetTargetLun
= &LsiScsiResetTargetLun
;
351 Dev
->PassThru
.GetNextTarget
= &LsiScsiGetNextTarget
;
353 Status
= gBS
->InstallProtocolInterface (
355 &gEfiExtScsiPassThruProtocolGuid
,
356 EFI_NATIVE_INTERFACE
,
359 if (EFI_ERROR (Status
)) {
373 LsiScsiControllerStop (
374 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
375 IN EFI_HANDLE ControllerHandle
,
376 IN UINTN NumberOfChildren
,
377 IN EFI_HANDLE
*ChildHandleBuffer
381 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
384 Status
= gBS
->OpenProtocol (
386 &gEfiExtScsiPassThruProtocolGuid
,
388 This
->DriverBindingHandle
,
390 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
392 if (EFI_ERROR (Status
)) {
396 Dev
= LSI_SCSI_FROM_PASS_THRU (PassThru
);
398 Status
= gBS
->UninstallProtocolInterface (
400 &gEfiExtScsiPassThruProtocolGuid
,
403 if (EFI_ERROR (Status
)) {
413 // The static object that groups the Supported() (ie. probe), Start() and
414 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
415 // C, 10.1 EFI Driver Binding Protocol.
418 EFI_DRIVER_BINDING_PROTOCOL gDriverBinding
= {
419 &LsiScsiControllerSupported
,
420 &LsiScsiControllerStart
,
421 &LsiScsiControllerStop
,
422 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
423 NULL
, // ImageHandle, to be overwritten by
424 // EfiLibInstallDriverBindingComponentName2() in LsiScsiEntryPoint()
425 NULL
// DriverBindingHandle, ditto
430 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
431 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
432 // in English, for display on standard console devices. This is recommended for
433 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
434 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
436 // Device type names ("LSI 53C895A SCSI Controller") are not formatted because
437 // the driver supports only that device type. Therefore the driver name
438 // suffices for unambiguous identification.
442 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
443 { "eng;en", L
"LSI 53C895A SCSI Controller Driver" },
448 EFI_COMPONENT_NAME_PROTOCOL gComponentName
;
452 LsiScsiGetDriverName (
453 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
455 OUT CHAR16
**DriverName
458 return LookupUnicodeString2 (
460 This
->SupportedLanguages
,
463 (BOOLEAN
)(This
== &gComponentName
) // Iso639Language
469 LsiScsiGetDeviceName (
470 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
471 IN EFI_HANDLE DeviceHandle
,
472 IN EFI_HANDLE ChildHandle
,
474 OUT CHAR16
**ControllerName
477 return EFI_UNSUPPORTED
;
481 EFI_COMPONENT_NAME_PROTOCOL gComponentName
= {
482 &LsiScsiGetDriverName
,
483 &LsiScsiGetDeviceName
,
484 "eng" // SupportedLanguages, ISO 639-2 language codes
488 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2
= {
489 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &LsiScsiGetDriverName
,
490 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &LsiScsiGetDeviceName
,
491 "en" // SupportedLanguages, RFC 4646 language codes
495 // Entry point of this driver
500 IN EFI_HANDLE ImageHandle
,
501 IN EFI_SYSTEM_TABLE
*SystemTable
504 return EfiLibInstallDriverBindingComponentName2 (
508 ImageHandle
, // The handle to install onto