3 This driver produces Extended SCSI Pass Thru Protocol instances for
6 Copyright (C) 2020, Oracle and/or its affiliates.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <IndustryStandard/Pci.h>
13 #include <IndustryStandard/PvScsi.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Library/UefiBootServicesTableLib.h>
17 #include <Library/UefiLib.h>
18 #include <Protocol/PciIo.h>
19 #include <Uefi/UefiSpec.h>
24 // Higher versions will be used before lower, 0x10-0xffffffef is the version
25 // range for IHV (Indie Hardware Vendors)
27 #define PVSCSI_BINDING_VERSION 0x10
30 // Ext SCSI Pass Thru utilities
34 Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
35 EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
45 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
; ++Idx
) {
46 if (Target
[Idx
] != 0xFF) {
61 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
64 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
65 IN EFI_EVENT Event OPTIONAL
68 return EFI_UNSUPPORTED
;
74 PvScsiGetNextTargetLun (
75 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
76 IN OUT UINT8
**Target
,
85 return EFI_INVALID_PARAMETER
;
89 // The Target input parameter is unnecessarily a pointer-to-pointer
94 // If target not initialized, return first target & LUN
96 if (!IsTargetInitialized (TargetPtr
)) {
97 ZeroMem (TargetPtr
, TARGET_MAX_BYTES
);
103 // We only use first byte of target identifer
105 LastTarget
= *TargetPtr
;
108 // Increment (target, LUN) pair if valid on input
110 Dev
= PVSCSI_FROM_PASS_THRU (This
);
111 if (LastTarget
> Dev
->MaxTarget
|| *Lun
> Dev
->MaxLun
) {
112 return EFI_INVALID_PARAMETER
;
115 if (*Lun
< Dev
->MaxLun
) {
120 if (LastTarget
< Dev
->MaxTarget
) {
123 *TargetPtr
= LastTarget
;
127 return EFI_NOT_FOUND
;
133 PvScsiBuildDevicePath (
134 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
137 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
142 SCSI_DEVICE_PATH
*ScsiDevicePath
;
144 if (DevicePath
== NULL
) {
145 return EFI_INVALID_PARAMETER
;
149 // We only use first byte of target identifer
151 TargetValue
= *Target
;
153 Dev
= PVSCSI_FROM_PASS_THRU (This
);
154 if (TargetValue
> Dev
->MaxTarget
|| Lun
> Dev
->MaxLun
) {
155 return EFI_NOT_FOUND
;
158 ScsiDevicePath
= AllocatePool (sizeof (*ScsiDevicePath
));
159 if (ScsiDevicePath
== NULL
) {
160 return EFI_OUT_OF_RESOURCES
;
163 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
164 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
165 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof (*ScsiDevicePath
);
166 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof (*ScsiDevicePath
) >> 8);
167 ScsiDevicePath
->Pun
= TargetValue
;
168 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
170 *DevicePath
= &ScsiDevicePath
->Header
;
178 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
179 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
184 SCSI_DEVICE_PATH
*ScsiDevicePath
;
187 if (DevicePath
== NULL
|| Target
== NULL
|| *Target
== NULL
|| Lun
== NULL
) {
188 return EFI_INVALID_PARAMETER
;
191 if (DevicePath
->Type
!= MESSAGING_DEVICE_PATH
||
192 DevicePath
->SubType
!= MSG_SCSI_DP
) {
193 return EFI_UNSUPPORTED
;
196 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
197 Dev
= PVSCSI_FROM_PASS_THRU (This
);
198 if (ScsiDevicePath
->Pun
> Dev
->MaxTarget
||
199 ScsiDevicePath
->Lun
> Dev
->MaxLun
) {
200 return EFI_NOT_FOUND
;
204 // We only use first byte of target identifer
206 **Target
= (UINT8
)ScsiDevicePath
->Pun
;
207 ZeroMem (*Target
+ 1, TARGET_MAX_BYTES
- 1);
208 *Lun
= ScsiDevicePath
->Lun
;
217 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
220 return EFI_UNSUPPORTED
;
226 PvScsiResetTargetLun (
227 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
232 return EFI_UNSUPPORTED
;
238 PvScsiGetNextTarget (
239 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
240 IN OUT UINT8
**Target
247 if (Target
== NULL
) {
248 return EFI_INVALID_PARAMETER
;
252 // The Target input parameter is unnecessarily a pointer-to-pointer
257 // If target not initialized, return first target
259 if (!IsTargetInitialized (TargetPtr
)) {
260 ZeroMem (TargetPtr
, TARGET_MAX_BYTES
);
265 // We only use first byte of target identifer
267 LastTarget
= *TargetPtr
;
270 // Increment target if valid on input
272 Dev
= PVSCSI_FROM_PASS_THRU (This
);
273 if (LastTarget
> Dev
->MaxTarget
) {
274 return EFI_INVALID_PARAMETER
;
277 if (LastTarget
< Dev
->MaxTarget
) {
279 *TargetPtr
= LastTarget
;
283 return EFI_NOT_FOUND
;
288 PvScsiSetPciAttributes (
289 IN OUT PVSCSI_DEV
*Dev
295 // Backup original PCI Attributes
297 Status
= Dev
->PciIo
->Attributes (
299 EfiPciIoAttributeOperationGet
,
301 &Dev
->OriginalPciAttributes
303 if (EFI_ERROR (Status
)) {
308 // Enable MMIO-Space & Bus-Mastering
310 Status
= Dev
->PciIo
->Attributes (
312 EfiPciIoAttributeOperationEnable
,
313 (EFI_PCI_IO_ATTRIBUTE_MEMORY
|
314 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
317 if (EFI_ERROR (Status
)) {
326 PvScsiRestorePciAttributes (
330 Dev
->PciIo
->Attributes (
332 EfiPciIoAttributeOperationSet
,
333 Dev
->OriginalPciAttributes
,
341 IN OUT PVSCSI_DEV
*Dev
347 // Init configuration
349 Dev
->MaxTarget
= PcdGet8 (PcdPvScsiMaxTargetLimit
);
350 Dev
->MaxLun
= PcdGet8 (PcdPvScsiMaxLunLimit
);
353 // Set PCI Attributes
355 Status
= PvScsiSetPciAttributes (Dev
);
356 if (EFI_ERROR (Status
)) {
361 // Populate the exported interface's attributes
363 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
364 Dev
->PassThru
.PassThru
= &PvScsiPassThru
;
365 Dev
->PassThru
.GetNextTargetLun
= &PvScsiGetNextTargetLun
;
366 Dev
->PassThru
.BuildDevicePath
= &PvScsiBuildDevicePath
;
367 Dev
->PassThru
.GetTargetLun
= &PvScsiGetTargetLun
;
368 Dev
->PassThru
.ResetChannel
= &PvScsiResetChannel
;
369 Dev
->PassThru
.ResetTargetLun
= &PvScsiResetTargetLun
;
370 Dev
->PassThru
.GetNextTarget
= &PvScsiGetNextTarget
;
373 // AdapterId is a target for which no handle will be created during bus scan.
374 // Prevent any conflict with real devices.
376 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
379 // Set both physical and logical attributes for non-RAID SCSI channel
381 Dev
->PassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
382 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
385 // No restriction on transfer buffer alignment
387 Dev
->PassThruMode
.IoAlign
= 0;
395 IN OUT PVSCSI_DEV
*Dev
398 PvScsiRestorePciAttributes (Dev
);
408 PvScsiDriverBindingSupported (
409 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
410 IN EFI_HANDLE ControllerHandle
,
411 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
415 EFI_PCI_IO_PROTOCOL
*PciIo
;
418 Status
= gBS
->OpenProtocol (
420 &gEfiPciIoProtocolGuid
,
422 This
->DriverBindingHandle
,
424 EFI_OPEN_PROTOCOL_BY_DRIVER
426 if (EFI_ERROR (Status
)) {
430 Status
= PciIo
->Pci
.Read (
434 sizeof (Pci
) / sizeof (UINT32
),
437 if (EFI_ERROR (Status
)) {
441 if ((Pci
.Hdr
.VendorId
!= PCI_VENDOR_ID_VMWARE
) ||
442 (Pci
.Hdr
.DeviceId
!= PCI_DEVICE_ID_VMWARE_PVSCSI
)) {
443 Status
= EFI_UNSUPPORTED
;
447 Status
= EFI_SUCCESS
;
452 &gEfiPciIoProtocolGuid
,
453 This
->DriverBindingHandle
,
463 PvScsiDriverBindingStart (
464 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
465 IN EFI_HANDLE ControllerHandle
,
466 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
472 Dev
= (PVSCSI_DEV
*) AllocateZeroPool (sizeof (*Dev
));
474 return EFI_OUT_OF_RESOURCES
;
477 Status
= gBS
->OpenProtocol (
479 &gEfiPciIoProtocolGuid
,
480 (VOID
**)&Dev
->PciIo
,
481 This
->DriverBindingHandle
,
483 EFI_OPEN_PROTOCOL_BY_DRIVER
485 if (EFI_ERROR (Status
)) {
489 Status
= PvScsiInit (Dev
);
490 if (EFI_ERROR (Status
)) {
495 // Setup complete, attempt to export the driver instance's PassThru interface
497 Dev
->Signature
= PVSCSI_SIG
;
498 Status
= gBS
->InstallProtocolInterface (
500 &gEfiExtScsiPassThruProtocolGuid
,
501 EFI_NATIVE_INTERFACE
,
504 if (EFI_ERROR (Status
)) {
516 &gEfiPciIoProtocolGuid
,
517 This
->DriverBindingHandle
,
530 PvScsiDriverBindingStop (
531 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
532 IN EFI_HANDLE ControllerHandle
,
533 IN UINTN NumberOfChildren
,
534 IN EFI_HANDLE
*ChildHandleBuffer
538 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
541 Status
= gBS
->OpenProtocol (
543 &gEfiExtScsiPassThruProtocolGuid
,
545 This
->DriverBindingHandle
,
547 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
549 if (EFI_ERROR (Status
)) {
553 Dev
= PVSCSI_FROM_PASS_THRU (PassThru
);
555 Status
= gBS
->UninstallProtocolInterface (
557 &gEfiExtScsiPassThruProtocolGuid
,
560 if (EFI_ERROR (Status
)) {
568 &gEfiPciIoProtocolGuid
,
569 This
->DriverBindingHandle
,
578 STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding
= {
579 &PvScsiDriverBindingSupported
,
580 &PvScsiDriverBindingStart
,
581 &PvScsiDriverBindingStop
,
582 PVSCSI_BINDING_VERSION
,
583 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
584 NULL
// DriverBindingHandle, filled as well
591 STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
592 { "eng;en", L
"PVSCSI Host Driver" },
596 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
601 PvScsiGetDriverName (
602 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
604 OUT CHAR16
**DriverName
607 return LookupUnicodeString2 (
609 This
->SupportedLanguages
,
612 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
619 PvScsiGetDeviceName (
620 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
621 IN EFI_HANDLE DeviceHandle
,
622 IN EFI_HANDLE ChildHandle
,
624 OUT CHAR16
**ControllerName
627 return EFI_UNSUPPORTED
;
630 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
631 &PvScsiGetDriverName
,
632 &PvScsiGetDeviceName
,
633 "eng" // SupportedLanguages, ISO 639-2 language codes
636 STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
637 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &PvScsiGetDriverName
,
638 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &PvScsiGetDeviceName
,
639 "en" // SupportedLanguages, RFC 4646 language codes
649 IN EFI_HANDLE ImageHandle
,
650 IN EFI_SYSTEM_TABLE
*SystemTable
653 return EfiLibInstallDriverBindingComponentName2 (
656 &mPvScsiDriverBinding
,