VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/PvScsiDxe/PvScsi.c

最後變更 在這個檔案是 101291,由 vboxsync 提交於 14 月 前

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 36.6 KB
 
1/** @file
2
3 This driver produces Extended SCSI Pass Thru Protocol instances for
4 pvscsi devices.
5
6 Copyright (C) 2020, Oracle and/or its affiliates.
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10**/
11
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>
22
23#include "PvScsi.h"
24
25//
26// Higher versions will be used before lower, 0x10-0xffffffef is the version
27// range for IHV (Indie Hardware Vendors)
28//
29#define PVSCSI_BINDING_VERSION 0x10
30
31//
32// Ext SCSI Pass Thru utilities
33//
34
35/**
36 Reads a 32-bit value into BAR0 using MMIO
37**/
38STATIC
39EFI_STATUS
40PvScsiMmioRead32 (
41 IN CONST PVSCSI_DEV *Dev,
42 IN UINT64 Offset,
43 OUT UINT32 *Value
44 )
45{
46 return Dev->PciIo->Mem.Read (
47 Dev->PciIo,
48 EfiPciIoWidthUint32,
49 PCI_BAR_IDX0,
50 Offset,
51 1, // Count
52 Value
53 );
54}
55
56/**
57 Writes a 32-bit value into BAR0 using MMIO
58**/
59STATIC
60EFI_STATUS
61PvScsiMmioWrite32 (
62 IN CONST PVSCSI_DEV *Dev,
63 IN UINT64 Offset,
64 IN UINT32 Value
65 )
66{
67 return Dev->PciIo->Mem.Write (
68 Dev->PciIo,
69 EfiPciIoWidthUint32,
70 PCI_BAR_IDX0,
71 Offset,
72 1, // Count
73 &Value
74 );
75}
76
77/**
78 Writes multiple words of data into BAR0 using MMIO
79**/
80STATIC
81EFI_STATUS
82PvScsiMmioWrite32Multiple (
83 IN CONST PVSCSI_DEV *Dev,
84 IN UINT64 Offset,
85 IN UINTN Count,
86 IN UINT32 *Words
87 )
88{
89 return Dev->PciIo->Mem.Write (
90 Dev->PciIo,
91 EfiPciIoWidthFifoUint32,
92 PCI_BAR_IDX0,
93 Offset,
94 Count,
95 Words
96 );
97}
98
99/**
100 Send a PVSCSI command to device.
101
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.
112
113 @return Status codes returned by Dev->PciIo->Mem.Write().
114
115**/
116STATIC
117EFI_STATUS
118PvScsiWriteCmdDesc (
119 IN CONST PVSCSI_DEV *Dev,
120 IN UINT32 Cmd,
121 IN UINT32 *DescWords OPTIONAL,
122 IN UINTN DescWordsCount
123 )
124{
125 EFI_STATUS Status;
126
127 if (DescWordsCount > PVSCSI_MAX_CMD_DATA_WORDS) {
128 return EFI_INVALID_PARAMETER;
129 }
130
131 Status = PvScsiMmioWrite32 (Dev, PvScsiRegOffsetCommand, Cmd);
132 if (EFI_ERROR (Status)) {
133 return Status;
134 }
135
136 if (DescWordsCount > 0) {
137 return PvScsiMmioWrite32Multiple (
138 Dev,
139 PvScsiRegOffsetCommandData,
140 DescWordsCount,
141 DescWords
142 );
143 }
144
145 return EFI_SUCCESS;
146}
147
148STATIC
149EFI_STATUS
150PvScsiResetAdapter (
151 IN CONST PVSCSI_DEV *Dev
152 )
153{
154 return PvScsiWriteCmdDesc (Dev, PvScsiCmdAdapterReset, NULL, 0);
155}
156
157/**
158 Returns if PVSCSI request ring is full
159**/
160STATIC
161BOOLEAN
162PvScsiIsReqRingFull (
163 IN CONST PVSCSI_DEV *Dev
164 )
165{
166 PVSCSI_RINGS_STATE *RingsState;
167 UINT32 ReqNumEntries;
168
169 RingsState = Dev->RingDesc.RingState;
170 ReqNumEntries = 1U << RingsState->ReqNumEntriesLog2;
171 return (RingsState->ReqProdIdx - RingsState->CmpConsIdx) >= ReqNumEntries;
172}
173
174/**
175 Returns pointer to current request descriptor to produce
176**/
177STATIC
178PVSCSI_RING_REQ_DESC *
179PvScsiGetCurrentRequest (
180 IN CONST PVSCSI_DEV *Dev
181 )
182{
183 PVSCSI_RINGS_STATE *RingState;
184 UINT32 ReqNumEntries;
185
186 RingState = Dev->RingDesc.RingState;
187 ReqNumEntries = 1U << RingState->ReqNumEntriesLog2;
188 return Dev->RingDesc.RingReqs +
189 (RingState->ReqProdIdx & (ReqNumEntries - 1));
190}
191
192/**
193 Returns pointer to current completion descriptor to consume
194**/
195STATIC
196PVSCSI_RING_CMP_DESC *
197PvScsiGetCurrentResponse (
198 IN CONST PVSCSI_DEV *Dev
199 )
200{
201 PVSCSI_RINGS_STATE *RingState;
202 UINT32 CmpNumEntries;
203
204 RingState = Dev->RingDesc.RingState;
205 CmpNumEntries = 1U << RingState->CmpNumEntriesLog2;
206 return Dev->RingDesc.RingCmps +
207 (RingState->CmpConsIdx & (CmpNumEntries - 1));
208}
209
210/**
211 Wait for device to signal completion of submitted requests
212**/
213STATIC
214EFI_STATUS
215PvScsiWaitForRequestCompletion (
216 IN CONST PVSCSI_DEV *Dev
217 )
218{
219 EFI_STATUS Status;
220 UINT32 IntrStatus;
221
222 //
223 // Note: We don't yet support Timeout according to
224 // EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.Timeout.
225 //
226 // This is consistent with some other Scsi PassThru drivers
227 // such as VirtioScsi.
228 //
229 for ( ; ;) {
230 Status = PvScsiMmioRead32 (Dev, PvScsiRegOffsetIntrStatus, &IntrStatus);
231 if (EFI_ERROR (Status)) {
232 return Status;
233 }
234
235 //
236 // PVSCSI_INTR_CMPL_MASK is set if device completed submitted requests
237 //
238 if ((IntrStatus & PVSCSI_INTR_CMPL_MASK) != 0) {
239 break;
240 }
241
242 gBS->Stall (Dev->WaitForCmpStallInUsecs);
243 }
244
245 //
246 // Acknowledge PVSCSI_INTR_CMPL_MASK in device interrupt-status register
247 //
248 return PvScsiMmioWrite32 (
249 Dev,
250 PvScsiRegOffsetIntrStatus,
251 PVSCSI_INTR_CMPL_MASK
252 );
253}
254
255/**
256 Create a fake host adapter error
257**/
258STATIC
259EFI_STATUS
260ReportHostAdapterError (
261 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
262 )
263{
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;
270}
271
272/**
273 Create a fake host adapter overrun error
274**/
275STATIC
276EFI_STATUS
277ReportHostAdapterOverrunError (
278 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
279 )
280{
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;
286}
287
288/**
289 Populate a PVSCSI request descriptor from the Extended SCSI Pass Thru
290 Protocol packet.
291**/
292STATIC
293EFI_STATUS
294PopulateRequest (
295 IN CONST PVSCSI_DEV *Dev,
296 IN UINT8 *Target,
297 IN UINT64 Lun,
298 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
299 OUT PVSCSI_RING_REQ_DESC *Request
300 )
301{
302 UINT8 TargetValue;
303
304 //
305 // We only use first byte of target identifer
306 //
307 TargetValue = *Target;
308
309 //
310 // Check for unsupported requests
311 //
312 if (
313 //
314 // Bidirectional transfer was requested
315 //
316 ((Packet->InTransferLength > 0) && (Packet->OutTransferLength > 0)) ||
317 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
318 //
319 // Command Descriptor Block bigger than this constant should be considered
320 // out-of-band. We currently don't support these CDBs.
321 //
322 (Packet->CdbLength > PVSCSI_CDB_MAX_SIZE)
323 )
324 {
325 //
326 // This error code doesn't require updates to the Packet output fields
327 //
328 return EFI_UNSUPPORTED;
329 }
330
331 //
332 // Check for invalid parameters
333 //
334 if (
335 //
336 // Addressed invalid device
337 //
338 (TargetValue > Dev->MaxTarget) || (Lun > Dev->MaxLun) ||
339 //
340 // Invalid direction (there doesn't seem to be a macro for the "no data
341 // transferred" "direction", eg. for TEST UNIT READY)
342 //
343 (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
344 //
345 // Trying to receive, but destination pointer is NULL, or contradicting
346 // transfer direction
347 //
348 ((Packet->InTransferLength > 0) &&
349 ((Packet->InDataBuffer == NULL) ||
350 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
351 )
352 ) ||
353 //
354 // Trying to send, but source pointer is NULL, or contradicting
355 // transfer direction
356 //
357 ((Packet->OutTransferLength > 0) &&
358 ((Packet->OutDataBuffer == NULL) ||
359 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
360 )
361 )
362 )
363 {
364 //
365 // This error code doesn't require updates to the Packet output fields
366 //
367 return EFI_INVALID_PARAMETER;
368 }
369
370 //
371 // Check for input/output buffer too large for DMA communication buffer
372 //
373 if (Packet->InTransferLength > sizeof (Dev->DmaBuf->Data)) {
374 Packet->InTransferLength = sizeof (Dev->DmaBuf->Data);
375 return ReportHostAdapterOverrunError (Packet);
376 }
377
378 if (Packet->OutTransferLength > sizeof (Dev->DmaBuf->Data)) {
379 Packet->OutTransferLength = sizeof (Dev->DmaBuf->Data);
380 return ReportHostAdapterOverrunError (Packet);
381 }
382
383 //
384 // Encode PVSCSI request
385 //
386 ZeroMem (Request, sizeof (*Request));
387
388 Request->Bus = 0;
389 Request->Target = TargetValue;
390 //
391 // This cast is safe as PVSCSI_DEV.MaxLun is defined as UINT8
392 //
393 Request->Lun[1] = (UINT8)Lun;
394 Request->SenseLen = Packet->SenseDataLength;
395 //
396 // DMA communication buffer SenseData overflow is not possible
397 // due to Packet->SenseDataLength defined as UINT8
398 //
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;
407 } else {
408 Request->Flags = PVSCSI_FLAG_CMD_DIR_TODEVICE;
409 Request->DataLen = Packet->OutTransferLength;
410 CopyMem (
411 Dev->DmaBuf->Data,
412 Packet->OutDataBuffer,
413 Packet->OutTransferLength
414 );
415 }
416
417 Request->DataAddr = PVSCSI_DMA_BUF_DEV_ADDR (Dev, Data);
418
419 return EFI_SUCCESS;
420}
421
422/**
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.
427**/
428STATIC
429EFI_STATUS
430HandleResponse (
431 IN PVSCSI_DEV *Dev,
432 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
433 IN CONST PVSCSI_RING_CMP_DESC *Response
434 )
435{
436 //
437 // Fix SenseDataLength to amount of data returned
438 //
439 if (Packet->SenseDataLength > Response->SenseLen) {
440 Packet->SenseDataLength = (UINT8)Response->SenseLen;
441 }
442
443 //
444 // Copy sense data from DMA communication buffer
445 //
446 CopyMem (
447 Packet->SenseData,
448 Dev->DmaBuf->SenseData,
449 Packet->SenseDataLength
450 );
451
452 //
453 // Copy device output from DMA communication buffer
454 //
455 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
456 CopyMem (Packet->InDataBuffer, Dev->DmaBuf->Data, Packet->InTransferLength);
457 }
458
459 //
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)
464 //
465 ASSERT (Response->ScsiStatus <= MAX_UINT8);
466 Packet->TargetStatus = (UINT8)Response->ScsiStatus;
467
468 //
469 // Host adapter status and function return value depend on
470 // device response's host status
471 //
472 switch (Response->HostStatus) {
473 case PvScsiBtStatSuccess:
474 case PvScsiBtStatLinkedCommandCompleted:
475 case PvScsiBtStatLinkedCommandCompletedWithFlag:
476 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
477 return EFI_SUCCESS;
478
479 case PvScsiBtStatDataUnderrun:
480 //
481 // Report transferred amount in underrun
482 //
483 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
484 Packet->InTransferLength = (UINT32)Response->DataLen;
485 } else {
486 Packet->OutTransferLength = (UINT32)Response->DataLen;
487 }
488
489 Packet->HostAdapterStatus =
490 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
491 return EFI_SUCCESS;
492
493 case PvScsiBtStatDatarun:
494 Packet->HostAdapterStatus =
495 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
496 return EFI_SUCCESS;
497
498 case PvScsiBtStatSelTimeout:
499 Packet->HostAdapterStatus =
500 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
501 return EFI_TIMEOUT;
502
503 case PvScsiBtStatBusFree:
504 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE;
505 break;
506
507 case PvScsiBtStatInvPhase:
508 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
509 break;
510
511 case PvScsiBtStatSensFailed:
512 Packet->HostAdapterStatus =
513 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED;
514 break;
515
516 case PvScsiBtStatTagReject:
517 case PvScsiBtStatBadMsg:
518 Packet->HostAdapterStatus =
519 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT;
520 break;
521
522 case PvScsiBtStatBusReset:
523 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
524 break;
525
526 case PvScsiBtStatHaTimeout:
527 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
528 return EFI_TIMEOUT;
529
530 case PvScsiBtStatScsiParity:
531 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
532 break;
533
534 default:
535 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
536 break;
537 }
538
539 return EFI_DEVICE_ERROR;
540}
541
542/**
543 Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
544 EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
545**/
546STATIC
547BOOLEAN
548IsTargetInitialized (
549 IN UINT8 *Target
550 )
551{
552 UINTN Idx;
553
554 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
555 if (Target[Idx] != 0xFF) {
556 return TRUE;
557 }
558 }
559
560 return FALSE;
561}
562
563//
564// Ext SCSI Pass Thru
565//
566
567STATIC
568EFI_STATUS
569EFIAPI
570PvScsiPassThru (
571 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
572 IN UINT8 *Target,
573 IN UINT64 Lun,
574 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
575 IN EFI_EVENT Event OPTIONAL
576 )
577{
578 PVSCSI_DEV *Dev;
579 EFI_STATUS Status;
580 PVSCSI_RING_REQ_DESC *Request;
581 PVSCSI_RING_CMP_DESC *Response;
582
583 Dev = PVSCSI_FROM_PASS_THRU (This);
584
585 if (PvScsiIsReqRingFull (Dev)) {
586 return EFI_NOT_READY;
587 }
588
589 Request = PvScsiGetCurrentRequest (Dev);
590
591 Status = PopulateRequest (Dev, Target, Lun, Packet, Request);
592 if (EFI_ERROR (Status)) {
593 return Status;
594 }
595
596 //
597 // Writes to Request must be globally visible before making request
598 // available to device
599 //
600 MemoryFence ();
601 Dev->RingDesc.RingState->ReqProdIdx++;
602
603 Status = PvScsiMmioWrite32 (Dev, PvScsiRegOffsetKickRwIo, 0);
604 if (EFI_ERROR (Status)) {
605 //
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
608 // the caller retry.
609 //
610 return ReportHostAdapterError (Packet);
611 }
612
613 Status = PvScsiWaitForRequestCompletion (Dev);
614 if (EFI_ERROR (Status)) {
615 //
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.
619 //
620 return ReportHostAdapterError (Packet);
621 }
622
623 Response = PvScsiGetCurrentResponse (Dev);
624 Status = HandleResponse (Dev, Packet, Response);
625
626 //
627 // Reads from response must complete before releasing completion entry
628 // to device
629 //
630 MemoryFence ();
631 Dev->RingDesc.RingState->CmpConsIdx++;
632
633 return Status;
634}
635
636STATIC
637EFI_STATUS
638EFIAPI
639PvScsiGetNextTargetLun (
640 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
641 IN OUT UINT8 **Target,
642 IN OUT UINT64 *Lun
643 )
644{
645 UINT8 *TargetPtr;
646 UINT8 LastTarget;
647 PVSCSI_DEV *Dev;
648
649 if (Target == NULL) {
650 return EFI_INVALID_PARAMETER;
651 }
652
653 //
654 // The Target input parameter is unnecessarily a pointer-to-pointer
655 //
656 TargetPtr = *Target;
657
658 //
659 // If target not initialized, return first target & LUN
660 //
661 if (!IsTargetInitialized (TargetPtr)) {
662 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
663 *Lun = 0;
664 return EFI_SUCCESS;
665 }
666
667 //
668 // We only use first byte of target identifer
669 //
670 LastTarget = *TargetPtr;
671
672 //
673 // Increment (target, LUN) pair if valid on input
674 //
675 Dev = PVSCSI_FROM_PASS_THRU (This);
676 if ((LastTarget > Dev->MaxTarget) || (*Lun > Dev->MaxLun)) {
677 return EFI_INVALID_PARAMETER;
678 }
679
680 if (*Lun < Dev->MaxLun) {
681 ++*Lun;
682 return EFI_SUCCESS;
683 }
684
685 if (LastTarget < Dev->MaxTarget) {
686 *Lun = 0;
687 ++LastTarget;
688 *TargetPtr = LastTarget;
689 return EFI_SUCCESS;
690 }
691
692 return EFI_NOT_FOUND;
693}
694
695STATIC
696EFI_STATUS
697EFIAPI
698PvScsiBuildDevicePath (
699 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
700 IN UINT8 *Target,
701 IN UINT64 Lun,
702 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
703 )
704{
705 UINT8 TargetValue;
706 PVSCSI_DEV *Dev;
707 SCSI_DEVICE_PATH *ScsiDevicePath;
708
709 if (DevicePath == NULL) {
710 return EFI_INVALID_PARAMETER;
711 }
712
713 //
714 // We only use first byte of target identifer
715 //
716 TargetValue = *Target;
717
718 Dev = PVSCSI_FROM_PASS_THRU (This);
719 if ((TargetValue > Dev->MaxTarget) || (Lun > Dev->MaxLun)) {
720 return EFI_NOT_FOUND;
721 }
722
723 ScsiDevicePath = AllocatePool (sizeof (*ScsiDevicePath));
724 if (ScsiDevicePath == NULL) {
725 return EFI_OUT_OF_RESOURCES;
726 }
727
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;
734
735 *DevicePath = &ScsiDevicePath->Header;
736 return EFI_SUCCESS;
737}
738
739STATIC
740EFI_STATUS
741EFIAPI
742PvScsiGetTargetLun (
743 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
744 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
745 OUT UINT8 **Target,
746 OUT UINT64 *Lun
747 )
748{
749 SCSI_DEVICE_PATH *ScsiDevicePath;
750 PVSCSI_DEV *Dev;
751
752 if ((DevicePath == NULL) || (Target == NULL) || (*Target == NULL) || (Lun == NULL)) {
753 return EFI_INVALID_PARAMETER;
754 }
755
756 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
757 (DevicePath->SubType != MSG_SCSI_DP))
758 {
759 return EFI_UNSUPPORTED;
760 }
761
762 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
763 Dev = PVSCSI_FROM_PASS_THRU (This);
764 if ((ScsiDevicePath->Pun > Dev->MaxTarget) ||
765 (ScsiDevicePath->Lun > Dev->MaxLun))
766 {
767 return EFI_NOT_FOUND;
768 }
769
770 //
771 // We only use first byte of target identifer
772 //
773 **Target = (UINT8)ScsiDevicePath->Pun;
774 ZeroMem (*Target + 1, TARGET_MAX_BYTES - 1);
775 *Lun = ScsiDevicePath->Lun;
776
777 return EFI_SUCCESS;
778}
779
780STATIC
781EFI_STATUS
782EFIAPI
783PvScsiResetChannel (
784 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
785 )
786{
787 return EFI_UNSUPPORTED;
788}
789
790STATIC
791EFI_STATUS
792EFIAPI
793PvScsiResetTargetLun (
794 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
795 IN UINT8 *Target,
796 IN UINT64 Lun
797 )
798{
799 return EFI_UNSUPPORTED;
800}
801
802STATIC
803EFI_STATUS
804EFIAPI
805PvScsiGetNextTarget (
806 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
807 IN OUT UINT8 **Target
808 )
809{
810 UINT8 *TargetPtr;
811 UINT8 LastTarget;
812 PVSCSI_DEV *Dev;
813
814 if (Target == NULL) {
815 return EFI_INVALID_PARAMETER;
816 }
817
818 //
819 // The Target input parameter is unnecessarily a pointer-to-pointer
820 //
821 TargetPtr = *Target;
822
823 //
824 // If target not initialized, return first target
825 //
826 if (!IsTargetInitialized (TargetPtr)) {
827 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
828 return EFI_SUCCESS;
829 }
830
831 //
832 // We only use first byte of target identifer
833 //
834 LastTarget = *TargetPtr;
835
836 //
837 // Increment target if valid on input
838 //
839 Dev = PVSCSI_FROM_PASS_THRU (This);
840 if (LastTarget > Dev->MaxTarget) {
841 return EFI_INVALID_PARAMETER;
842 }
843
844 if (LastTarget < Dev->MaxTarget) {
845 ++LastTarget;
846 *TargetPtr = LastTarget;
847 return EFI_SUCCESS;
848 }
849
850 return EFI_NOT_FOUND;
851}
852
853STATIC
854EFI_STATUS
855PvScsiSetPciAttributes (
856 IN OUT PVSCSI_DEV *Dev
857 )
858{
859 EFI_STATUS Status;
860
861 //
862 // Backup original PCI Attributes
863 //
864 Status = Dev->PciIo->Attributes (
865 Dev->PciIo,
866 EfiPciIoAttributeOperationGet,
867 0,
868 &Dev->OriginalPciAttributes
869 );
870 if (EFI_ERROR (Status)) {
871 return Status;
872 }
873
874 //
875 // Enable MMIO-Space & Bus-Mastering
876 //
877 Status = Dev->PciIo->Attributes (
878 Dev->PciIo,
879 EfiPciIoAttributeOperationEnable,
880 (EFI_PCI_IO_ATTRIBUTE_MEMORY |
881 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
882 NULL
883 );
884 if (EFI_ERROR (Status)) {
885 return Status;
886 }
887
888 //
889 // Signal device supports 64-bit DMA addresses
890 //
891 Status = Dev->PciIo->Attributes (
892 Dev->PciIo,
893 EfiPciIoAttributeOperationEnable,
894 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
895 NULL
896 );
897 if (EFI_ERROR (Status)) {
898 //
899 // Warn user that device will only be using 32-bit DMA addresses.
900 //
901 // Note that this does not prevent the device/driver from working
902 // and therefore we only warn and continue as usual.
903 //
904 DEBUG ((
905 DEBUG_WARN,
906 "%a: failed to enable 64-bit DMA addresses\n",
907 __func__
908 ));
909 }
910
911 return EFI_SUCCESS;
912}
913
914STATIC
915VOID
916PvScsiRestorePciAttributes (
917 IN PVSCSI_DEV *Dev
918 )
919{
920 Dev->PciIo->Attributes (
921 Dev->PciIo,
922 EfiPciIoAttributeOperationSet,
923 Dev->OriginalPciAttributes,
924 NULL
925 );
926}
927
928STATIC
929EFI_STATUS
930PvScsiAllocateSharedPages (
931 IN PVSCSI_DEV *Dev,
932 IN UINTN Pages,
933 OUT VOID **HostAddress,
934 OUT PVSCSI_DMA_DESC *DmaDesc
935 )
936{
937 EFI_STATUS Status;
938 UINTN NumberOfBytes;
939
940 Status = Dev->PciIo->AllocateBuffer (
941 Dev->PciIo,
942 AllocateAnyPages,
943 EfiBootServicesData,
944 Pages,
945 HostAddress,
946 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
947 );
948 if (EFI_ERROR (Status)) {
949 return Status;
950 }
951
952 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
953 Status = Dev->PciIo->Map (
954 Dev->PciIo,
955 EfiPciIoOperationBusMasterCommonBuffer,
956 *HostAddress,
957 &NumberOfBytes,
958 &DmaDesc->DeviceAddress,
959 &DmaDesc->Mapping
960 );
961 if (EFI_ERROR (Status)) {
962 goto FreeBuffer;
963 }
964
965 if (NumberOfBytes != EFI_PAGES_TO_SIZE (Pages)) {
966 Status = EFI_OUT_OF_RESOURCES;
967 goto Unmap;
968 }
969
970 return EFI_SUCCESS;
971
972Unmap:
973 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
974
975FreeBuffer:
976 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, *HostAddress);
977
978 return Status;
979}
980
981STATIC
982VOID
983PvScsiFreeSharedPages (
984 IN PVSCSI_DEV *Dev,
985 IN UINTN Pages,
986 IN VOID *HostAddress,
987 IN PVSCSI_DMA_DESC *DmaDesc
988 )
989{
990 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
991 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, HostAddress);
992}
993
994STATIC
995EFI_STATUS
996PvScsiInitRings (
997 IN OUT PVSCSI_DEV *Dev
998 )
999{
1000 EFI_STATUS Status;
1001
1002 Status = PvScsiAllocateSharedPages (
1003 Dev,
1004 1,
1005 (VOID **)&Dev->RingDesc.RingState,
1006 &Dev->RingDesc.RingStateDmaDesc
1007 );
1008 if (EFI_ERROR (Status)) {
1009 return Status;
1010 }
1011
1012 ZeroMem (Dev->RingDesc.RingState, EFI_PAGE_SIZE);
1013
1014 Status = PvScsiAllocateSharedPages (
1015 Dev,
1016 1,
1017 (VOID **)&Dev->RingDesc.RingReqs,
1018 &Dev->RingDesc.RingReqsDmaDesc
1019 );
1020 if (EFI_ERROR (Status)) {
1021 goto FreeRingState;
1022 }
1023
1024 ZeroMem (Dev->RingDesc.RingReqs, EFI_PAGE_SIZE);
1025
1026 Status = PvScsiAllocateSharedPages (
1027 Dev,
1028 1,
1029 (VOID **)&Dev->RingDesc.RingCmps,
1030 &Dev->RingDesc.RingCmpsDmaDesc
1031 );
1032 if (EFI_ERROR (Status)) {
1033 goto FreeRingReqs;
1034 }
1035
1036 ZeroMem (Dev->RingDesc.RingCmps, EFI_PAGE_SIZE);
1037
1038 return EFI_SUCCESS;
1039
1040FreeRingReqs:
1041 PvScsiFreeSharedPages (
1042 Dev,
1043 1,
1044 Dev->RingDesc.RingReqs,
1045 &Dev->RingDesc.RingReqsDmaDesc
1046 );
1047
1048FreeRingState:
1049 PvScsiFreeSharedPages (
1050 Dev,
1051 1,
1052 Dev->RingDesc.RingState,
1053 &Dev->RingDesc.RingStateDmaDesc
1054 );
1055
1056 return Status;
1057}
1058
1059STATIC
1060VOID
1061PvScsiFreeRings (
1062 IN OUT PVSCSI_DEV *Dev
1063 )
1064{
1065 PvScsiFreeSharedPages (
1066 Dev,
1067 1,
1068 Dev->RingDesc.RingCmps,
1069 &Dev->RingDesc.RingCmpsDmaDesc
1070 );
1071
1072 PvScsiFreeSharedPages (
1073 Dev,
1074 1,
1075 Dev->RingDesc.RingReqs,
1076 &Dev->RingDesc.RingReqsDmaDesc
1077 );
1078
1079 PvScsiFreeSharedPages (
1080 Dev,
1081 1,
1082 Dev->RingDesc.RingState,
1083 &Dev->RingDesc.RingStateDmaDesc
1084 );
1085}
1086
1087STATIC
1088EFI_STATUS
1089PvScsiSetupRings (
1090 IN OUT PVSCSI_DEV *Dev
1091 )
1092{
1093 union {
1094 PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
1095 UINT32 Uint32;
1096 } AlignedCmd;
1097 PVSCSI_CMD_DESC_SETUP_RINGS *Cmd;
1098
1099 Cmd = &AlignedCmd.Cmd;
1100
1101 ZeroMem (Cmd, sizeof (*Cmd));
1102 Cmd->ReqRingNumPages = 1;
1103 Cmd->CmpRingNumPages = 1;
1104 Cmd->RingsStatePPN = RShiftU64 (
1105 Dev->RingDesc.RingStateDmaDesc.DeviceAddress,
1106 EFI_PAGE_SHIFT
1107 );
1108 Cmd->ReqRingPPNs[0] = RShiftU64 (
1109 Dev->RingDesc.RingReqsDmaDesc.DeviceAddress,
1110 EFI_PAGE_SHIFT
1111 );
1112 Cmd->CmpRingPPNs[0] = RShiftU64 (
1113 Dev->RingDesc.RingCmpsDmaDesc.DeviceAddress,
1114 EFI_PAGE_SHIFT
1115 );
1116
1117 STATIC_ASSERT (
1118 sizeof (*Cmd) % sizeof (UINT32) == 0,
1119 "Cmd must be multiple of 32-bit words"
1120 );
1121 return PvScsiWriteCmdDesc (
1122 Dev,
1123 PvScsiCmdSetupRings,
1124 (UINT32 *)Cmd,
1125 sizeof (*Cmd) / sizeof (UINT32)
1126 );
1127}
1128
1129STATIC
1130EFI_STATUS
1131PvScsiInit (
1132 IN OUT PVSCSI_DEV *Dev
1133 )
1134{
1135 EFI_STATUS Status;
1136
1137 //
1138 // Init configuration
1139 //
1140 Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
1141 Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
1142 Dev->WaitForCmpStallInUsecs = PcdGet32 (PcdPvScsiWaitForCmpStallInUsecs);
1143
1144 //
1145 // Set PCI Attributes
1146 //
1147 Status = PvScsiSetPciAttributes (Dev);
1148 if (EFI_ERROR (Status)) {
1149 return Status;
1150 }
1151
1152 //
1153 // Reset adapter
1154 //
1155 Status = PvScsiResetAdapter (Dev);
1156 if (EFI_ERROR (Status)) {
1157 goto RestorePciAttributes;
1158 }
1159
1160 //
1161 // Init PVSCSI rings
1162 //
1163 Status = PvScsiInitRings (Dev);
1164 if (EFI_ERROR (Status)) {
1165 goto RestorePciAttributes;
1166 }
1167
1168 //
1169 // Allocate DMA communication buffer
1170 //
1171 Status = PvScsiAllocateSharedPages (
1172 Dev,
1173 EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
1174 (VOID **)&Dev->DmaBuf,
1175 &Dev->DmaBufDmaDesc
1176 );
1177 if (EFI_ERROR (Status)) {
1178 goto FreeRings;
1179 }
1180
1181 //
1182 // Setup rings against device
1183 //
1184 Status = PvScsiSetupRings (Dev);
1185 if (EFI_ERROR (Status)) {
1186 goto FreeDmaCommBuffer;
1187 }
1188
1189 //
1190 // Populate the exported interface's attributes
1191 //
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;
1200
1201 //
1202 // AdapterId is a target for which no handle will be created during bus scan.
1203 // Prevent any conflict with real devices.
1204 //
1205 Dev->PassThruMode.AdapterId = MAX_UINT32;
1206
1207 //
1208 // Set both physical and logical attributes for non-RAID SCSI channel
1209 //
1210 Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
1211 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
1212
1213 //
1214 // No restriction on transfer buffer alignment
1215 //
1216 Dev->PassThruMode.IoAlign = 0;
1217
1218 return EFI_SUCCESS;
1219
1220FreeDmaCommBuffer:
1221 PvScsiFreeSharedPages (
1222 Dev,
1223 EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
1224 Dev->DmaBuf,
1225 &Dev->DmaBufDmaDesc
1226 );
1227
1228FreeRings:
1229 PvScsiFreeRings (Dev);
1230
1231RestorePciAttributes:
1232 PvScsiRestorePciAttributes (Dev);
1233
1234 return Status;
1235}
1236
1237STATIC
1238VOID
1239PvScsiUninit (
1240 IN OUT PVSCSI_DEV *Dev
1241 )
1242{
1243 //
1244 // Reset device to:
1245 // - Make device stop processing all requests.
1246 // - Stop device usage of the rings.
1247 //
1248 // This is required to safely free the DMA communication buffer
1249 // and the rings.
1250 //
1251 PvScsiResetAdapter (Dev);
1252
1253 //
1254 // Free DMA communication buffer
1255 //
1256 PvScsiFreeSharedPages (
1257 Dev,
1258 EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
1259 Dev->DmaBuf,
1260 &Dev->DmaBufDmaDesc
1261 );
1262
1263 PvScsiFreeRings (Dev);
1264
1265 PvScsiRestorePciAttributes (Dev);
1266}
1267
1268/**
1269 Event notification called by ExitBootServices()
1270**/
1271STATIC
1272VOID
1273EFIAPI
1274PvScsiExitBoot (
1275 IN EFI_EVENT Event,
1276 IN VOID *Context
1277 )
1278{
1279 PVSCSI_DEV *Dev;
1280
1281 Dev = Context;
1282 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __func__, Context));
1283
1284 //
1285 // Reset the device to stop device usage of the rings.
1286 //
1287 // We allocated said rings in EfiBootServicesData type memory, and code
1288 // executing after ExitBootServices() is permitted to overwrite it.
1289 //
1290 PvScsiResetAdapter (Dev);
1291}
1292
1293//
1294// Driver Binding
1295//
1296
1297STATIC
1298EFI_STATUS
1299EFIAPI
1300PvScsiDriverBindingSupported (
1301 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1302 IN EFI_HANDLE ControllerHandle,
1303 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1304 )
1305{
1306 EFI_STATUS Status;
1307 EFI_PCI_IO_PROTOCOL *PciIo;
1308 PCI_TYPE00 Pci;
1309
1310 Status = gBS->OpenProtocol (
1311 ControllerHandle,
1312 &gEfiPciIoProtocolGuid,
1313 (VOID **)&PciIo,
1314 This->DriverBindingHandle,
1315 ControllerHandle,
1316 EFI_OPEN_PROTOCOL_BY_DRIVER
1317 );
1318 if (EFI_ERROR (Status)) {
1319 return Status;
1320 }
1321
1322 Status = PciIo->Pci.Read (
1323 PciIo,
1324 EfiPciIoWidthUint32,
1325 0,
1326 sizeof (Pci) / sizeof (UINT32),
1327 &Pci
1328 );
1329 if (EFI_ERROR (Status)) {
1330 goto Done;
1331 }
1332
1333 if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||
1334 (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI))
1335 {
1336 Status = EFI_UNSUPPORTED;
1337 goto Done;
1338 }
1339
1340 Status = EFI_SUCCESS;
1341
1342Done:
1343 gBS->CloseProtocol (
1344 ControllerHandle,
1345 &gEfiPciIoProtocolGuid,
1346 This->DriverBindingHandle,
1347 ControllerHandle
1348 );
1349
1350 return Status;
1351}
1352
1353STATIC
1354EFI_STATUS
1355EFIAPI
1356PvScsiDriverBindingStart (
1357 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1358 IN EFI_HANDLE ControllerHandle,
1359 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1360 )
1361{
1362 PVSCSI_DEV *Dev;
1363 EFI_STATUS Status;
1364
1365 Dev = (PVSCSI_DEV *)AllocateZeroPool (sizeof (*Dev));
1366 if (Dev == NULL) {
1367 return EFI_OUT_OF_RESOURCES;
1368 }
1369
1370 Status = gBS->OpenProtocol (
1371 ControllerHandle,
1372 &gEfiPciIoProtocolGuid,
1373 (VOID **)&Dev->PciIo,
1374 This->DriverBindingHandle,
1375 ControllerHandle,
1376 EFI_OPEN_PROTOCOL_BY_DRIVER
1377 );
1378 if (EFI_ERROR (Status)) {
1379 goto FreePvScsi;
1380 }
1381
1382 Status = PvScsiInit (Dev);
1383 if (EFI_ERROR (Status)) {
1384 goto ClosePciIo;
1385 }
1386
1387 Status = gBS->CreateEvent (
1388 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1389 TPL_CALLBACK,
1390 &PvScsiExitBoot,
1391 Dev,
1392 &Dev->ExitBoot
1393 );
1394 if (EFI_ERROR (Status)) {
1395 goto UninitDev;
1396 }
1397
1398 //
1399 // Setup complete, attempt to export the driver instance's PassThru interface
1400 //
1401 Dev->Signature = PVSCSI_SIG;
1402 Status = gBS->InstallProtocolInterface (
1403 &ControllerHandle,
1404 &gEfiExtScsiPassThruProtocolGuid,
1405 EFI_NATIVE_INTERFACE,
1406 &Dev->PassThru
1407 );
1408 if (EFI_ERROR (Status)) {
1409 goto CloseExitBoot;
1410 }
1411
1412 return EFI_SUCCESS;
1413
1414CloseExitBoot:
1415 gBS->CloseEvent (Dev->ExitBoot);
1416
1417UninitDev:
1418 PvScsiUninit (Dev);
1419
1420ClosePciIo:
1421 gBS->CloseProtocol (
1422 ControllerHandle,
1423 &gEfiPciIoProtocolGuid,
1424 This->DriverBindingHandle,
1425 ControllerHandle
1426 );
1427
1428FreePvScsi:
1429 FreePool (Dev);
1430
1431 return Status;
1432}
1433
1434STATIC
1435EFI_STATUS
1436EFIAPI
1437PvScsiDriverBindingStop (
1438 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1439 IN EFI_HANDLE ControllerHandle,
1440 IN UINTN NumberOfChildren,
1441 IN EFI_HANDLE *ChildHandleBuffer
1442 )
1443{
1444 EFI_STATUS Status;
1445 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
1446 PVSCSI_DEV *Dev;
1447
1448 Status = gBS->OpenProtocol (
1449 ControllerHandle,
1450 &gEfiExtScsiPassThruProtocolGuid,
1451 (VOID **)&PassThru,
1452 This->DriverBindingHandle,
1453 ControllerHandle,
1454 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
1455 );
1456 if (EFI_ERROR (Status)) {
1457 return Status;
1458 }
1459
1460 Dev = PVSCSI_FROM_PASS_THRU (PassThru);
1461
1462 Status = gBS->UninstallProtocolInterface (
1463 ControllerHandle,
1464 &gEfiExtScsiPassThruProtocolGuid,
1465 &Dev->PassThru
1466 );
1467 if (EFI_ERROR (Status)) {
1468 return Status;
1469 }
1470
1471 gBS->CloseEvent (Dev->ExitBoot);
1472
1473 PvScsiUninit (Dev);
1474
1475 gBS->CloseProtocol (
1476 ControllerHandle,
1477 &gEfiPciIoProtocolGuid,
1478 This->DriverBindingHandle,
1479 ControllerHandle
1480 );
1481
1482 FreePool (Dev);
1483
1484 return EFI_SUCCESS;
1485}
1486
1487STATIC 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
1494};
1495
1496//
1497// Component Name
1498//
1499
1500STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1501 { "eng;en", L"PVSCSI Host Driver" },
1502 { NULL, NULL }
1503};
1504
1505STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1506
1507STATIC
1508EFI_STATUS
1509EFIAPI
1510PvScsiGetDriverName (
1511 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1512 IN CHAR8 *Language,
1513 OUT CHAR16 **DriverName
1514 )
1515{
1516 return LookupUnicodeString2 (
1517 Language,
1518 This->SupportedLanguages,
1519 mDriverNameTable,
1520 DriverName,
1521 (BOOLEAN)(This == &mComponentName) // Iso639Language
1522 );
1523}
1524
1525STATIC
1526EFI_STATUS
1527EFIAPI
1528PvScsiGetDeviceName (
1529 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1530 IN EFI_HANDLE DeviceHandle,
1531 IN EFI_HANDLE ChildHandle,
1532 IN CHAR8 *Language,
1533 OUT CHAR16 **ControllerName
1534 )
1535{
1536 return EFI_UNSUPPORTED;
1537}
1538
1539STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1540 &PvScsiGetDriverName,
1541 &PvScsiGetDeviceName,
1542 "eng" // SupportedLanguages, ISO 639-2 language codes
1543};
1544
1545STATIC 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
1549};
1550
1551//
1552// Entry Point
1553//
1554
1555EFI_STATUS
1556EFIAPI
1557PvScsiEntryPoint (
1558 IN EFI_HANDLE ImageHandle,
1559 IN EFI_SYSTEM_TABLE *SystemTable
1560 )
1561{
1562 return EfiLibInstallDriverBindingComponentName2 (
1563 ImageHandle,
1564 SystemTable,
1565 &mPvScsiDriverBinding,
1566 ImageHandle,
1567 &mComponentName,
1568 &mComponentName2
1569 );
1570}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette