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/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiLib.h>
19 #include <Protocol/PciIo.h>
20 #include <Protocol/PciRootBridgeIo.h>
21 #include <Uefi/UefiSpec.h>
26 // Higher versions will be used before lower, 0x10-0xffffffef is the version
27 // range for IHV (Indie Hardware Vendors)
29 #define PVSCSI_BINDING_VERSION 0x10
32 // Ext SCSI Pass Thru utilities
36 Reads a 32-bit value into BAR0 using MMIO
41 IN CONST PVSCSI_DEV
*Dev
,
46 return Dev
->PciIo
->Mem
.Read (
57 Writes a 32-bit value into BAR0 using MMIO
62 IN CONST PVSCSI_DEV
*Dev
,
67 return Dev
->PciIo
->Mem
.Write (
78 Writes multiple words of data into BAR0 using MMIO
82 PvScsiMmioWrite32Multiple (
83 IN CONST PVSCSI_DEV
*Dev
,
89 return Dev
->PciIo
->Mem
.Write (
91 EfiPciIoWidthFifoUint32
,
100 Send a PVSCSI command to device.
102 @param[in] Dev The pvscsi host device.
103 @param[in] Cmd The command to send to device.
104 @param[in] OPTIONAL DescWords An optional command descriptor (If command
105 have a descriptor). The descriptor is
106 provided as an array of UINT32 words and
107 is must be 32-bit aligned.
108 @param[in] DescWordsCount The number of words in command descriptor.
109 Caller must specify here 0 if DescWords
110 is not supplied (It is optional). In that
111 case, DescWords is ignored.
113 @return Status codes returned by Dev->PciIo->Mem.Write().
119 IN CONST PVSCSI_DEV
*Dev
,
121 IN UINT32
*DescWords OPTIONAL
,
122 IN UINTN DescWordsCount
127 if (DescWordsCount
> PVSCSI_MAX_CMD_DATA_WORDS
) {
128 return EFI_INVALID_PARAMETER
;
131 Status
= PvScsiMmioWrite32 (Dev
, PvScsiRegOffsetCommand
, Cmd
);
132 if (EFI_ERROR (Status
)) {
136 if (DescWordsCount
> 0) {
137 return PvScsiMmioWrite32Multiple (
139 PvScsiRegOffsetCommandData
,
151 IN CONST PVSCSI_DEV
*Dev
154 return PvScsiWriteCmdDesc (Dev
, PvScsiCmdAdapterReset
, NULL
, 0);
158 Returns if PVSCSI request ring is full
162 PvScsiIsReqRingFull (
163 IN CONST PVSCSI_DEV
*Dev
166 PVSCSI_RINGS_STATE
*RingsState
;
167 UINT32 ReqNumEntries
;
169 RingsState
= Dev
->RingDesc
.RingState
;
170 ReqNumEntries
= 1U << RingsState
->ReqNumEntriesLog2
;
171 return (RingsState
->ReqProdIdx
- RingsState
->CmpConsIdx
) >= ReqNumEntries
;
175 Returns pointer to current request descriptor to produce
178 PVSCSI_RING_REQ_DESC
*
179 PvScsiGetCurrentRequest (
180 IN CONST PVSCSI_DEV
*Dev
183 PVSCSI_RINGS_STATE
*RingState
;
184 UINT32 ReqNumEntries
;
186 RingState
= Dev
->RingDesc
.RingState
;
187 ReqNumEntries
= 1U << RingState
->ReqNumEntriesLog2
;
188 return Dev
->RingDesc
.RingReqs
+
189 (RingState
->ReqProdIdx
& (ReqNumEntries
- 1));
193 Returns pointer to current completion descriptor to consume
196 PVSCSI_RING_CMP_DESC
*
197 PvScsiGetCurrentResponse (
198 IN CONST PVSCSI_DEV
*Dev
201 PVSCSI_RINGS_STATE
*RingState
;
202 UINT32 CmpNumEntries
;
204 RingState
= Dev
->RingDesc
.RingState
;
205 CmpNumEntries
= 1U << RingState
->CmpNumEntriesLog2
;
206 return Dev
->RingDesc
.RingCmps
+
207 (RingState
->CmpConsIdx
& (CmpNumEntries
- 1));
211 Wait for device to signal completion of submitted requests
215 PvScsiWaitForRequestCompletion (
216 IN CONST PVSCSI_DEV
*Dev
223 // Note: We don't yet support Timeout according to
224 // EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.Timeout.
226 // This is consistent with some other Scsi PassThru drivers
227 // such as VirtioScsi.
230 Status
= PvScsiMmioRead32 (Dev
, PvScsiRegOffsetIntrStatus
, &IntrStatus
);
231 if (EFI_ERROR (Status
)) {
236 // PVSCSI_INTR_CMPL_MASK is set if device completed submitted requests
238 if ((IntrStatus
& PVSCSI_INTR_CMPL_MASK
) != 0) {
242 gBS
->Stall (Dev
->WaitForCmpStallInUsecs
);
246 // Acknowledge PVSCSI_INTR_CMPL_MASK in device interrupt-status register
248 return PvScsiMmioWrite32 (
250 PvScsiRegOffsetIntrStatus
,
251 PVSCSI_INTR_CMPL_MASK
256 Create a fake host adapter error
260 ReportHostAdapterError (
261 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
264 Packet
->InTransferLength
= 0;
265 Packet
->OutTransferLength
= 0;
266 Packet
->SenseDataLength
= 0;
267 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
268 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
269 return EFI_DEVICE_ERROR
;
273 Create a fake host adapter overrun error
277 ReportHostAdapterOverrunError (
278 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
281 Packet
->SenseDataLength
= 0;
282 Packet
->HostAdapterStatus
=
283 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
284 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
285 return EFI_BAD_BUFFER_SIZE
;
289 Populate a PVSCSI request descriptor from the Extended SCSI Pass Thru
295 IN CONST PVSCSI_DEV
*Dev
,
298 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
299 OUT PVSCSI_RING_REQ_DESC
*Request
305 // We only use first byte of target identifer
307 TargetValue
= *Target
;
310 // Check for unsupported requests
314 // Bidirectional transfer was requested
316 ((Packet
->InTransferLength
> 0) && (Packet
->OutTransferLength
> 0)) ||
317 (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
) ||
319 // Command Descriptor Block bigger than this constant should be considered
320 // out-of-band. We currently don't support these CDBs.
322 (Packet
->CdbLength
> PVSCSI_CDB_MAX_SIZE
)
326 // This error code doesn't require updates to the Packet output fields
328 return EFI_UNSUPPORTED
;
332 // Check for invalid parameters
336 // Addressed invalid device
338 (TargetValue
> Dev
->MaxTarget
) || (Lun
> Dev
->MaxLun
) ||
340 // Invalid direction (there doesn't seem to be a macro for the "no data
341 // transferred" "direction", eg. for TEST UNIT READY)
343 (Packet
->DataDirection
> EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
) ||
345 // Trying to receive, but destination pointer is NULL, or contradicting
346 // transfer direction
348 ((Packet
->InTransferLength
> 0) &&
349 ((Packet
->InDataBuffer
== NULL
) ||
350 (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_WRITE
)
354 // Trying to send, but source pointer is NULL, or contradicting
355 // transfer direction
357 ((Packet
->OutTransferLength
> 0) &&
358 ((Packet
->OutDataBuffer
== NULL
) ||
359 (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
)
365 // This error code doesn't require updates to the Packet output fields
367 return EFI_INVALID_PARAMETER
;
371 // Check for input/output buffer too large for DMA communication buffer
373 if (Packet
->InTransferLength
> sizeof (Dev
->DmaBuf
->Data
)) {
374 Packet
->InTransferLength
= sizeof (Dev
->DmaBuf
->Data
);
375 return ReportHostAdapterOverrunError (Packet
);
378 if (Packet
->OutTransferLength
> sizeof (Dev
->DmaBuf
->Data
)) {
379 Packet
->OutTransferLength
= sizeof (Dev
->DmaBuf
->Data
);
380 return ReportHostAdapterOverrunError (Packet
);
384 // Encode PVSCSI request
386 ZeroMem (Request
, sizeof (*Request
));
389 Request
->Target
= TargetValue
;
391 // This cast is safe as PVSCSI_DEV.MaxLun is defined as UINT8
393 Request
->Lun
[1] = (UINT8
)Lun
;
394 Request
->SenseLen
= Packet
->SenseDataLength
;
396 // DMA communication buffer SenseData overflow is not possible
397 // due to Packet->SenseDataLength defined as UINT8
399 Request
->SenseAddr
= PVSCSI_DMA_BUF_DEV_ADDR (Dev
, SenseData
);
400 Request
->CdbLen
= Packet
->CdbLength
;
401 CopyMem (Request
->Cdb
, Packet
->Cdb
, Packet
->CdbLength
);
402 Request
->VcpuHint
= 0;
403 Request
->Tag
= PVSCSI_SIMPLE_QUEUE_TAG
;
404 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
405 Request
->Flags
= PVSCSI_FLAG_CMD_DIR_TOHOST
;
406 Request
->DataLen
= Packet
->InTransferLength
;
408 Request
->Flags
= PVSCSI_FLAG_CMD_DIR_TODEVICE
;
409 Request
->DataLen
= Packet
->OutTransferLength
;
412 Packet
->OutDataBuffer
,
413 Packet
->OutTransferLength
417 Request
->DataAddr
= PVSCSI_DMA_BUF_DEV_ADDR (Dev
, Data
);
423 Handle the PVSCSI device response:
424 - Copy returned data from DMA communication buffer.
425 - Update fields in Extended SCSI Pass Thru Protocol packet as required.
426 - Translate response code to EFI status code and host adapter status.
432 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
433 IN CONST PVSCSI_RING_CMP_DESC
*Response
437 // Fix SenseDataLength to amount of data returned
439 if (Packet
->SenseDataLength
> Response
->SenseLen
) {
440 Packet
->SenseDataLength
= (UINT8
)Response
->SenseLen
;
444 // Copy sense data from DMA communication buffer
448 Dev
->DmaBuf
->SenseData
,
449 Packet
->SenseDataLength
453 // Copy device output from DMA communication buffer
455 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
456 CopyMem (Packet
->InDataBuffer
, Dev
->DmaBuf
->Data
, Packet
->InTransferLength
);
460 // Report target status
461 // (Strangely, PVSCSI interface defines Response->ScsiStatus as UINT16.
462 // But it should de-facto always have a value that fits UINT8. To avoid
463 // unexpected behavior, verify value is in UINT8 bounds before casting)
465 ASSERT (Response
->ScsiStatus
<= MAX_UINT8
);
466 Packet
->TargetStatus
= (UINT8
)Response
->ScsiStatus
;
469 // Host adapter status and function return value depend on
470 // device response's host status
472 switch (Response
->HostStatus
) {
473 case PvScsiBtStatSuccess
:
474 case PvScsiBtStatLinkedCommandCompleted
:
475 case PvScsiBtStatLinkedCommandCompletedWithFlag
:
476 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
479 case PvScsiBtStatDataUnderrun
:
481 // Report transferred amount in underrun
483 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
484 Packet
->InTransferLength
= (UINT32
)Response
->DataLen
;
486 Packet
->OutTransferLength
= (UINT32
)Response
->DataLen
;
489 Packet
->HostAdapterStatus
=
490 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
493 case PvScsiBtStatDatarun
:
494 Packet
->HostAdapterStatus
=
495 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
498 case PvScsiBtStatSelTimeout
:
499 Packet
->HostAdapterStatus
=
500 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
;
503 case PvScsiBtStatBusFree
:
504 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
;
507 case PvScsiBtStatInvPhase
:
508 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
511 case PvScsiBtStatSensFailed
:
512 Packet
->HostAdapterStatus
=
513 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
;
516 case PvScsiBtStatTagReject
:
517 case PvScsiBtStatBadMsg
:
518 Packet
->HostAdapterStatus
=
519 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
;
522 case PvScsiBtStatBusReset
:
523 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
;
526 case PvScsiBtStatHaTimeout
:
527 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
;
530 case PvScsiBtStatScsiParity
:
531 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
;
535 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
539 return EFI_DEVICE_ERROR
;
543 Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
544 EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
548 IsTargetInitialized (
554 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
; ++Idx
) {
555 if (Target
[Idx
] != 0xFF) {
564 // Ext SCSI Pass Thru
571 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
574 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
575 IN EFI_EVENT Event OPTIONAL
580 PVSCSI_RING_REQ_DESC
*Request
;
581 PVSCSI_RING_CMP_DESC
*Response
;
583 Dev
= PVSCSI_FROM_PASS_THRU (This
);
585 if (PvScsiIsReqRingFull (Dev
)) {
586 return EFI_NOT_READY
;
589 Request
= PvScsiGetCurrentRequest (Dev
);
591 Status
= PopulateRequest (Dev
, Target
, Lun
, Packet
, Request
);
592 if (EFI_ERROR (Status
)) {
597 // Writes to Request must be globally visible before making request
598 // available to device
601 Dev
->RingDesc
.RingState
->ReqProdIdx
++;
603 Status
= PvScsiMmioWrite32 (Dev
, PvScsiRegOffsetKickRwIo
, 0);
604 if (EFI_ERROR (Status
)) {
606 // If kicking the host fails, we must fake a host adapter error.
607 // EFI_NOT_READY would save us the effort, but it would also suggest that
610 return ReportHostAdapterError (Packet
);
613 Status
= PvScsiWaitForRequestCompletion (Dev
);
614 if (EFI_ERROR (Status
)) {
616 // If waiting for request completion fails, we must fake a host adapter
617 // error. EFI_NOT_READY would save us the effort, but it would also suggest
618 // that the caller retry.
620 return ReportHostAdapterError (Packet
);
623 Response
= PvScsiGetCurrentResponse (Dev
);
624 Status
= HandleResponse (Dev
, Packet
, Response
);
627 // Reads from response must complete before releasing completion entry
631 Dev
->RingDesc
.RingState
->CmpConsIdx
++;
639 PvScsiGetNextTargetLun (
640 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
641 IN OUT UINT8
**Target
,
649 if (Target
== NULL
) {
650 return EFI_INVALID_PARAMETER
;
654 // The Target input parameter is unnecessarily a pointer-to-pointer
659 // If target not initialized, return first target & LUN
661 if (!IsTargetInitialized (TargetPtr
)) {
662 ZeroMem (TargetPtr
, TARGET_MAX_BYTES
);
668 // We only use first byte of target identifer
670 LastTarget
= *TargetPtr
;
673 // Increment (target, LUN) pair if valid on input
675 Dev
= PVSCSI_FROM_PASS_THRU (This
);
676 if ((LastTarget
> Dev
->MaxTarget
) || (*Lun
> Dev
->MaxLun
)) {
677 return EFI_INVALID_PARAMETER
;
680 if (*Lun
< Dev
->MaxLun
) {
685 if (LastTarget
< Dev
->MaxTarget
) {
688 *TargetPtr
= LastTarget
;
692 return EFI_NOT_FOUND
;
698 PvScsiBuildDevicePath (
699 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
702 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
707 SCSI_DEVICE_PATH
*ScsiDevicePath
;
709 if (DevicePath
== NULL
) {
710 return EFI_INVALID_PARAMETER
;
714 // We only use first byte of target identifer
716 TargetValue
= *Target
;
718 Dev
= PVSCSI_FROM_PASS_THRU (This
);
719 if ((TargetValue
> Dev
->MaxTarget
) || (Lun
> Dev
->MaxLun
)) {
720 return EFI_NOT_FOUND
;
723 ScsiDevicePath
= AllocatePool (sizeof (*ScsiDevicePath
));
724 if (ScsiDevicePath
== NULL
) {
725 return EFI_OUT_OF_RESOURCES
;
728 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
729 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
730 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof (*ScsiDevicePath
);
731 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof (*ScsiDevicePath
) >> 8);
732 ScsiDevicePath
->Pun
= TargetValue
;
733 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
735 *DevicePath
= &ScsiDevicePath
->Header
;
743 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
744 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
749 SCSI_DEVICE_PATH
*ScsiDevicePath
;
752 if ((DevicePath
== NULL
) || (Target
== NULL
) || (*Target
== NULL
) || (Lun
== NULL
)) {
753 return EFI_INVALID_PARAMETER
;
756 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
757 (DevicePath
->SubType
!= MSG_SCSI_DP
))
759 return EFI_UNSUPPORTED
;
762 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
763 Dev
= PVSCSI_FROM_PASS_THRU (This
);
764 if ((ScsiDevicePath
->Pun
> Dev
->MaxTarget
) ||
765 (ScsiDevicePath
->Lun
> Dev
->MaxLun
))
767 return EFI_NOT_FOUND
;
771 // We only use first byte of target identifer
773 **Target
= (UINT8
)ScsiDevicePath
->Pun
;
774 ZeroMem (*Target
+ 1, TARGET_MAX_BYTES
- 1);
775 *Lun
= ScsiDevicePath
->Lun
;
784 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
787 return EFI_UNSUPPORTED
;
793 PvScsiResetTargetLun (
794 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
799 return EFI_UNSUPPORTED
;
805 PvScsiGetNextTarget (
806 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
807 IN OUT UINT8
**Target
814 if (Target
== NULL
) {
815 return EFI_INVALID_PARAMETER
;
819 // The Target input parameter is unnecessarily a pointer-to-pointer
824 // If target not initialized, return first target
826 if (!IsTargetInitialized (TargetPtr
)) {
827 ZeroMem (TargetPtr
, TARGET_MAX_BYTES
);
832 // We only use first byte of target identifer
834 LastTarget
= *TargetPtr
;
837 // Increment target if valid on input
839 Dev
= PVSCSI_FROM_PASS_THRU (This
);
840 if (LastTarget
> Dev
->MaxTarget
) {
841 return EFI_INVALID_PARAMETER
;
844 if (LastTarget
< Dev
->MaxTarget
) {
846 *TargetPtr
= LastTarget
;
850 return EFI_NOT_FOUND
;
855 PvScsiSetPciAttributes (
856 IN OUT PVSCSI_DEV
*Dev
862 // Backup original PCI Attributes
864 Status
= Dev
->PciIo
->Attributes (
866 EfiPciIoAttributeOperationGet
,
868 &Dev
->OriginalPciAttributes
870 if (EFI_ERROR (Status
)) {
875 // Enable MMIO-Space & Bus-Mastering
877 Status
= Dev
->PciIo
->Attributes (
879 EfiPciIoAttributeOperationEnable
,
880 (EFI_PCI_IO_ATTRIBUTE_MEMORY
|
881 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
884 if (EFI_ERROR (Status
)) {
889 // Signal device supports 64-bit DMA addresses
891 Status
= Dev
->PciIo
->Attributes (
893 EfiPciIoAttributeOperationEnable
,
894 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
897 if (EFI_ERROR (Status
)) {
899 // Warn user that device will only be using 32-bit DMA addresses.
901 // Note that this does not prevent the device/driver from working
902 // and therefore we only warn and continue as usual.
906 "%a: failed to enable 64-bit DMA addresses\n",
916 PvScsiRestorePciAttributes (
920 Dev
->PciIo
->Attributes (
922 EfiPciIoAttributeOperationSet
,
923 Dev
->OriginalPciAttributes
,
930 PvScsiAllocateSharedPages (
933 OUT VOID
**HostAddress
,
934 OUT PVSCSI_DMA_DESC
*DmaDesc
940 Status
= Dev
->PciIo
->AllocateBuffer (
946 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
948 if (EFI_ERROR (Status
)) {
952 NumberOfBytes
= EFI_PAGES_TO_SIZE (Pages
);
953 Status
= Dev
->PciIo
->Map (
955 EfiPciIoOperationBusMasterCommonBuffer
,
958 &DmaDesc
->DeviceAddress
,
961 if (EFI_ERROR (Status
)) {
965 if (NumberOfBytes
!= EFI_PAGES_TO_SIZE (Pages
)) {
966 Status
= EFI_OUT_OF_RESOURCES
;
973 Dev
->PciIo
->Unmap (Dev
->PciIo
, DmaDesc
->Mapping
);
976 Dev
->PciIo
->FreeBuffer (Dev
->PciIo
, Pages
, *HostAddress
);
983 PvScsiFreeSharedPages (
986 IN VOID
*HostAddress
,
987 IN PVSCSI_DMA_DESC
*DmaDesc
990 Dev
->PciIo
->Unmap (Dev
->PciIo
, DmaDesc
->Mapping
);
991 Dev
->PciIo
->FreeBuffer (Dev
->PciIo
, Pages
, HostAddress
);
997 IN OUT PVSCSI_DEV
*Dev
1002 Status
= PvScsiAllocateSharedPages (
1005 (VOID
**)&Dev
->RingDesc
.RingState
,
1006 &Dev
->RingDesc
.RingStateDmaDesc
1008 if (EFI_ERROR (Status
)) {
1012 ZeroMem (Dev
->RingDesc
.RingState
, EFI_PAGE_SIZE
);
1014 Status
= PvScsiAllocateSharedPages (
1017 (VOID
**)&Dev
->RingDesc
.RingReqs
,
1018 &Dev
->RingDesc
.RingReqsDmaDesc
1020 if (EFI_ERROR (Status
)) {
1024 ZeroMem (Dev
->RingDesc
.RingReqs
, EFI_PAGE_SIZE
);
1026 Status
= PvScsiAllocateSharedPages (
1029 (VOID
**)&Dev
->RingDesc
.RingCmps
,
1030 &Dev
->RingDesc
.RingCmpsDmaDesc
1032 if (EFI_ERROR (Status
)) {
1036 ZeroMem (Dev
->RingDesc
.RingCmps
, EFI_PAGE_SIZE
);
1041 PvScsiFreeSharedPages (
1044 Dev
->RingDesc
.RingReqs
,
1045 &Dev
->RingDesc
.RingReqsDmaDesc
1049 PvScsiFreeSharedPages (
1052 Dev
->RingDesc
.RingState
,
1053 &Dev
->RingDesc
.RingStateDmaDesc
1062 IN OUT PVSCSI_DEV
*Dev
1065 PvScsiFreeSharedPages (
1068 Dev
->RingDesc
.RingCmps
,
1069 &Dev
->RingDesc
.RingCmpsDmaDesc
1072 PvScsiFreeSharedPages (
1075 Dev
->RingDesc
.RingReqs
,
1076 &Dev
->RingDesc
.RingReqsDmaDesc
1079 PvScsiFreeSharedPages (
1082 Dev
->RingDesc
.RingState
,
1083 &Dev
->RingDesc
.RingStateDmaDesc
1090 IN OUT PVSCSI_DEV
*Dev
1094 PVSCSI_CMD_DESC_SETUP_RINGS Cmd
;
1097 PVSCSI_CMD_DESC_SETUP_RINGS
*Cmd
;
1099 Cmd
= &AlignedCmd
.Cmd
;
1101 ZeroMem (Cmd
, sizeof (*Cmd
));
1102 Cmd
->ReqRingNumPages
= 1;
1103 Cmd
->CmpRingNumPages
= 1;
1104 Cmd
->RingsStatePPN
= RShiftU64 (
1105 Dev
->RingDesc
.RingStateDmaDesc
.DeviceAddress
,
1108 Cmd
->ReqRingPPNs
[0] = RShiftU64 (
1109 Dev
->RingDesc
.RingReqsDmaDesc
.DeviceAddress
,
1112 Cmd
->CmpRingPPNs
[0] = RShiftU64 (
1113 Dev
->RingDesc
.RingCmpsDmaDesc
.DeviceAddress
,
1118 sizeof (*Cmd
) % sizeof (UINT32
) == 0,
1119 "Cmd must be multiple of 32-bit words"
1121 return PvScsiWriteCmdDesc (
1123 PvScsiCmdSetupRings
,
1125 sizeof (*Cmd
) / sizeof (UINT32
)
1132 IN OUT PVSCSI_DEV
*Dev
1138 // Init configuration
1140 Dev
->MaxTarget
= PcdGet8 (PcdPvScsiMaxTargetLimit
);
1141 Dev
->MaxLun
= PcdGet8 (PcdPvScsiMaxLunLimit
);
1142 Dev
->WaitForCmpStallInUsecs
= PcdGet32 (PcdPvScsiWaitForCmpStallInUsecs
);
1145 // Set PCI Attributes
1147 Status
= PvScsiSetPciAttributes (Dev
);
1148 if (EFI_ERROR (Status
)) {
1155 Status
= PvScsiResetAdapter (Dev
);
1156 if (EFI_ERROR (Status
)) {
1157 goto RestorePciAttributes
;
1161 // Init PVSCSI rings
1163 Status
= PvScsiInitRings (Dev
);
1164 if (EFI_ERROR (Status
)) {
1165 goto RestorePciAttributes
;
1169 // Allocate DMA communication buffer
1171 Status
= PvScsiAllocateSharedPages (
1173 EFI_SIZE_TO_PAGES (sizeof (*Dev
->DmaBuf
)),
1174 (VOID
**)&Dev
->DmaBuf
,
1177 if (EFI_ERROR (Status
)) {
1182 // Setup rings against device
1184 Status
= PvScsiSetupRings (Dev
);
1185 if (EFI_ERROR (Status
)) {
1186 goto FreeDmaCommBuffer
;
1190 // Populate the exported interface's attributes
1192 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
1193 Dev
->PassThru
.PassThru
= &PvScsiPassThru
;
1194 Dev
->PassThru
.GetNextTargetLun
= &PvScsiGetNextTargetLun
;
1195 Dev
->PassThru
.BuildDevicePath
= &PvScsiBuildDevicePath
;
1196 Dev
->PassThru
.GetTargetLun
= &PvScsiGetTargetLun
;
1197 Dev
->PassThru
.ResetChannel
= &PvScsiResetChannel
;
1198 Dev
->PassThru
.ResetTargetLun
= &PvScsiResetTargetLun
;
1199 Dev
->PassThru
.GetNextTarget
= &PvScsiGetNextTarget
;
1202 // AdapterId is a target for which no handle will be created during bus scan.
1203 // Prevent any conflict with real devices.
1205 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
1208 // Set both physical and logical attributes for non-RAID SCSI channel
1210 Dev
->PassThruMode
.Attributes
= EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
1211 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
1214 // No restriction on transfer buffer alignment
1216 Dev
->PassThruMode
.IoAlign
= 0;
1221 PvScsiFreeSharedPages (
1223 EFI_SIZE_TO_PAGES (sizeof (*Dev
->DmaBuf
)),
1229 PvScsiFreeRings (Dev
);
1231 RestorePciAttributes
:
1232 PvScsiRestorePciAttributes (Dev
);
1240 IN OUT PVSCSI_DEV
*Dev
1245 // - Make device stop processing all requests.
1246 // - Stop device usage of the rings.
1248 // This is required to safely free the DMA communication buffer
1251 PvScsiResetAdapter (Dev
);
1254 // Free DMA communication buffer
1256 PvScsiFreeSharedPages (
1258 EFI_SIZE_TO_PAGES (sizeof (*Dev
->DmaBuf
)),
1263 PvScsiFreeRings (Dev
);
1265 PvScsiRestorePciAttributes (Dev
);
1269 Event notification called by ExitBootServices()
1282 DEBUG ((DEBUG_VERBOSE
, "%a: Context=0x%p\n", __FUNCTION__
, Context
));
1285 // Reset the device to stop device usage of the rings.
1287 // We allocated said rings in EfiBootServicesData type memory, and code
1288 // executing after ExitBootServices() is permitted to overwrite it.
1290 PvScsiResetAdapter (Dev
);
1300 PvScsiDriverBindingSupported (
1301 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1302 IN EFI_HANDLE ControllerHandle
,
1303 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
1307 EFI_PCI_IO_PROTOCOL
*PciIo
;
1310 Status
= gBS
->OpenProtocol (
1312 &gEfiPciIoProtocolGuid
,
1314 This
->DriverBindingHandle
,
1316 EFI_OPEN_PROTOCOL_BY_DRIVER
1318 if (EFI_ERROR (Status
)) {
1322 Status
= PciIo
->Pci
.Read (
1324 EfiPciIoWidthUint32
,
1326 sizeof (Pci
) / sizeof (UINT32
),
1329 if (EFI_ERROR (Status
)) {
1333 if ((Pci
.Hdr
.VendorId
!= PCI_VENDOR_ID_VMWARE
) ||
1334 (Pci
.Hdr
.DeviceId
!= PCI_DEVICE_ID_VMWARE_PVSCSI
))
1336 Status
= EFI_UNSUPPORTED
;
1340 Status
= EFI_SUCCESS
;
1343 gBS
->CloseProtocol (
1345 &gEfiPciIoProtocolGuid
,
1346 This
->DriverBindingHandle
,
1356 PvScsiDriverBindingStart (
1357 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1358 IN EFI_HANDLE ControllerHandle
,
1359 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
1365 Dev
= (PVSCSI_DEV
*)AllocateZeroPool (sizeof (*Dev
));
1367 return EFI_OUT_OF_RESOURCES
;
1370 Status
= gBS
->OpenProtocol (
1372 &gEfiPciIoProtocolGuid
,
1373 (VOID
**)&Dev
->PciIo
,
1374 This
->DriverBindingHandle
,
1376 EFI_OPEN_PROTOCOL_BY_DRIVER
1378 if (EFI_ERROR (Status
)) {
1382 Status
= PvScsiInit (Dev
);
1383 if (EFI_ERROR (Status
)) {
1387 Status
= gBS
->CreateEvent (
1388 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
1394 if (EFI_ERROR (Status
)) {
1399 // Setup complete, attempt to export the driver instance's PassThru interface
1401 Dev
->Signature
= PVSCSI_SIG
;
1402 Status
= gBS
->InstallProtocolInterface (
1404 &gEfiExtScsiPassThruProtocolGuid
,
1405 EFI_NATIVE_INTERFACE
,
1408 if (EFI_ERROR (Status
)) {
1415 gBS
->CloseEvent (Dev
->ExitBoot
);
1421 gBS
->CloseProtocol (
1423 &gEfiPciIoProtocolGuid
,
1424 This
->DriverBindingHandle
,
1437 PvScsiDriverBindingStop (
1438 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1439 IN EFI_HANDLE ControllerHandle
,
1440 IN UINTN NumberOfChildren
,
1441 IN EFI_HANDLE
*ChildHandleBuffer
1445 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
1448 Status
= gBS
->OpenProtocol (
1450 &gEfiExtScsiPassThruProtocolGuid
,
1452 This
->DriverBindingHandle
,
1454 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
1456 if (EFI_ERROR (Status
)) {
1460 Dev
= PVSCSI_FROM_PASS_THRU (PassThru
);
1462 Status
= gBS
->UninstallProtocolInterface (
1464 &gEfiExtScsiPassThruProtocolGuid
,
1467 if (EFI_ERROR (Status
)) {
1471 gBS
->CloseEvent (Dev
->ExitBoot
);
1475 gBS
->CloseProtocol (
1477 &gEfiPciIoProtocolGuid
,
1478 This
->DriverBindingHandle
,
1487 STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding
= {
1488 &PvScsiDriverBindingSupported
,
1489 &PvScsiDriverBindingStart
,
1490 &PvScsiDriverBindingStop
,
1491 PVSCSI_BINDING_VERSION
,
1492 NULL
, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
1493 NULL
// DriverBindingHandle, filled as well
1500 STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1501 { "eng;en", L
"PVSCSI Host Driver" },
1505 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1510 PvScsiGetDriverName (
1511 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1513 OUT CHAR16
**DriverName
1516 return LookupUnicodeString2 (
1518 This
->SupportedLanguages
,
1521 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1528 PvScsiGetDeviceName (
1529 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1530 IN EFI_HANDLE DeviceHandle
,
1531 IN EFI_HANDLE ChildHandle
,
1533 OUT CHAR16
**ControllerName
1536 return EFI_UNSUPPORTED
;
1539 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1540 &PvScsiGetDriverName
,
1541 &PvScsiGetDeviceName
,
1542 "eng" // SupportedLanguages, ISO 639-2 language codes
1545 STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1546 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
)&PvScsiGetDriverName
,
1547 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
)&PvScsiGetDeviceName
,
1548 "en" // SupportedLanguages, RFC 4646 language codes
1558 IN EFI_HANDLE ImageHandle
,
1559 IN EFI_SYSTEM_TABLE
*SystemTable
1562 return EfiLibInstallDriverBindingComponentName2 (
1565 &mPvScsiDriverBinding
,