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
;
289 IN OUT PVSCSI_DEV
*Dev
293 // Init configuration
295 Dev
->MaxTarget
= PcdGet8 (PcdPvScsiMaxTargetLimit
);
296 Dev
->MaxLun
= PcdGet8 (PcdPvScsiMaxLunLimit
);
299 // Populate the exported interface's attributes
301 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
302 Dev
->PassThru
.PassThru
= &PvScsiPassThru
;
303 Dev
->PassThru
.GetNextTargetLun
= &PvScsiGetNextTargetLun
;
304 Dev
->PassThru
.BuildDevicePath
= &PvScsiBuildDevicePath
;
305 Dev
->PassThru
.GetTargetLun
= &PvScsiGetTargetLun
;
306 Dev
->PassThru
.ResetChannel
= &PvScsiResetChannel
;
307 Dev
->PassThru
.ResetTargetLun
= &PvScsiResetTargetLun
;
308 Dev
->PassThru
.GetNextTarget
= &PvScsiGetNextTarget
;
311 // AdapterId is a target for which no handle will be created during bus scan.
312 // Prevent any conflict with real devices.
314 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
317 // Set both physical and logical attributes for non-RAID SCSI channel
319 Dev
->PassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
320 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
323 // No restriction on transfer buffer alignment
325 Dev
->PassThruMode
.IoAlign
= 0;
333 IN OUT PVSCSI_DEV
*Dev
336 // Currently nothing to do here
346 PvScsiDriverBindingSupported (
347 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
348 IN EFI_HANDLE ControllerHandle
,
349 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
353 EFI_PCI_IO_PROTOCOL
*PciIo
;
356 Status
= gBS
->OpenProtocol (
358 &gEfiPciIoProtocolGuid
,
360 This
->DriverBindingHandle
,
362 EFI_OPEN_PROTOCOL_BY_DRIVER
364 if (EFI_ERROR (Status
)) {
368 Status
= PciIo
->Pci
.Read (
372 sizeof (Pci
) / sizeof (UINT32
),
375 if (EFI_ERROR (Status
)) {
379 if ((Pci
.Hdr
.VendorId
!= PCI_VENDOR_ID_VMWARE
) ||
380 (Pci
.Hdr
.DeviceId
!= PCI_DEVICE_ID_VMWARE_PVSCSI
)) {
381 Status
= EFI_UNSUPPORTED
;
385 Status
= EFI_SUCCESS
;
390 &gEfiPciIoProtocolGuid
,
391 This
->DriverBindingHandle
,
401 PvScsiDriverBindingStart (
402 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
403 IN EFI_HANDLE ControllerHandle
,
404 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
410 Dev
= (PVSCSI_DEV
*) AllocateZeroPool (sizeof (*Dev
));
412 return EFI_OUT_OF_RESOURCES
;
415 Status
= PvScsiInit (Dev
);
416 if (EFI_ERROR (Status
)) {
421 // Setup complete, attempt to export the driver instance's PassThru interface
423 Dev
->Signature
= PVSCSI_SIG
;
424 Status
= gBS
->InstallProtocolInterface (
426 &gEfiExtScsiPassThruProtocolGuid
,
427 EFI_NATIVE_INTERFACE
,
430 if (EFI_ERROR (Status
)) {
448 PvScsiDriverBindingStop (
449 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
450 IN EFI_HANDLE ControllerHandle
,
451 IN UINTN NumberOfChildren
,
452 IN EFI_HANDLE
*ChildHandleBuffer
456 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
459 Status
= gBS
->OpenProtocol (
461 &gEfiExtScsiPassThruProtocolGuid
,
463 This
->DriverBindingHandle
,
465 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
467 if (EFI_ERROR (Status
)) {
471 Dev
= PVSCSI_FROM_PASS_THRU (PassThru
);
473 Status
= gBS
->UninstallProtocolInterface (
475 &gEfiExtScsiPassThruProtocolGuid
,
478 if (EFI_ERROR (Status
)) {
489 STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding
= {
490 &PvScsiDriverBindingSupported
,
491 &PvScsiDriverBindingStart
,
492 &PvScsiDriverBindingStop
,
493 PVSCSI_BINDING_VERSION
,
494 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
495 NULL
// DriverBindingHandle, filled as well
502 STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
503 { "eng;en", L
"PVSCSI Host Driver" },
507 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
512 PvScsiGetDriverName (
513 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
515 OUT CHAR16
**DriverName
518 return LookupUnicodeString2 (
520 This
->SupportedLanguages
,
523 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
530 PvScsiGetDeviceName (
531 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
532 IN EFI_HANDLE DeviceHandle
,
533 IN EFI_HANDLE ChildHandle
,
535 OUT CHAR16
**ControllerName
538 return EFI_UNSUPPORTED
;
541 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
542 &PvScsiGetDriverName
,
543 &PvScsiGetDeviceName
,
544 "eng" // SupportedLanguages, ISO 639-2 language codes
547 STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
548 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &PvScsiGetDriverName
,
549 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &PvScsiGetDeviceName
,
550 "en" // SupportedLanguages, RFC 4646 language codes
560 IN EFI_HANDLE ImageHandle
,
561 IN EFI_SYSTEM_TABLE
*SystemTable
564 return EfiLibInstallDriverBindingComponentName2 (
567 &mPvScsiDriverBinding
,