]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PvScsiDxe/PvScsi.c
OvmfPkg/PvScsiDxe: Fix VS2019 build error because of implicit cast
[mirror_edk2.git] / OvmfPkg / PvScsiDxe / PvScsi.c
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 **/
38 STATIC
39 EFI_STATUS
40 PvScsiMmioRead32 (
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 **/
59 STATIC
60 EFI_STATUS
61 PvScsiMmioWrite32 (
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 **/
80 STATIC
81 EFI_STATUS
82 PvScsiMmioWrite32Multiple (
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 **/
116 STATIC
117 EFI_STATUS
118 PvScsiWriteCmdDesc (
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
148 STATIC
149 EFI_STATUS
150 PvScsiResetAdapter (
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 **/
160 STATIC
161 BOOLEAN
162 PvScsiIsReqRingFull (
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 **/
177 STATIC
178 PVSCSI_RING_REQ_DESC *
179 PvScsiGetCurrentRequest (
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 **/
195 STATIC
196 PVSCSI_RING_CMP_DESC *
197 PvScsiGetCurrentResponse (
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 **/
213 STATIC
214 EFI_STATUS
215 PvScsiWaitForRequestCompletion (
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 **/
258 STATIC
259 EFI_STATUS
260 ReportHostAdapterError (
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 **/
275 STATIC
276 EFI_STATUS
277 ReportHostAdapterOverrunError (
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 **/
292 STATIC
293 EFI_STATUS
294 PopulateRequest (
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 if (Packet->OutTransferLength > sizeof (Dev->DmaBuf->Data)) {
378 Packet->OutTransferLength = sizeof (Dev->DmaBuf->Data);
379 return ReportHostAdapterOverrunError (Packet);
380 }
381
382 //
383 // Encode PVSCSI request
384 //
385 ZeroMem (Request, sizeof (*Request));
386
387 Request->Bus = 0;
388 Request->Target = TargetValue;
389 //
390 // This cast is safe as PVSCSI_DEV.MaxLun is defined as UINT8
391 //
392 Request->Lun[1] = (UINT8)Lun;
393 Request->SenseLen = Packet->SenseDataLength;
394 //
395 // DMA communication buffer SenseData overflow is not possible
396 // due to Packet->SenseDataLength defined as UINT8
397 //
398 Request->SenseAddr = PVSCSI_DMA_BUF_DEV_ADDR (Dev, SenseData);
399 Request->CdbLen = Packet->CdbLength;
400 CopyMem (Request->Cdb, Packet->Cdb, Packet->CdbLength);
401 Request->VcpuHint = 0;
402 Request->Tag = PVSCSI_SIMPLE_QUEUE_TAG;
403 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
404 Request->Flags = PVSCSI_FLAG_CMD_DIR_TOHOST;
405 Request->DataLen = Packet->InTransferLength;
406 } else {
407 Request->Flags = PVSCSI_FLAG_CMD_DIR_TODEVICE;
408 Request->DataLen = Packet->OutTransferLength;
409 CopyMem (
410 Dev->DmaBuf->Data,
411 Packet->OutDataBuffer,
412 Packet->OutTransferLength
413 );
414 }
415 Request->DataAddr = PVSCSI_DMA_BUF_DEV_ADDR (Dev, Data);
416
417 return EFI_SUCCESS;
418 }
419
420 /**
421 Handle the PVSCSI device response:
422 - Copy returned data from DMA communication buffer.
423 - Update fields in Extended SCSI Pass Thru Protocol packet as required.
424 - Translate response code to EFI status code and host adapter status.
425 **/
426 STATIC
427 EFI_STATUS
428 HandleResponse (
429 IN PVSCSI_DEV *Dev,
430 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
431 IN CONST PVSCSI_RING_CMP_DESC *Response
432 )
433 {
434 //
435 // Fix SenseDataLength to amount of data returned
436 //
437 if (Packet->SenseDataLength > Response->SenseLen) {
438 Packet->SenseDataLength = (UINT8)Response->SenseLen;
439 }
440 //
441 // Copy sense data from DMA communication buffer
442 //
443 CopyMem (
444 Packet->SenseData,
445 Dev->DmaBuf->SenseData,
446 Packet->SenseDataLength
447 );
448
449 //
450 // Copy device output from DMA communication buffer
451 //
452 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
453 CopyMem (Packet->InDataBuffer, Dev->DmaBuf->Data, Packet->InTransferLength);
454 }
455
456 //
457 // Report target status
458 // (Strangely, PVSCSI interface defines Response->ScsiStatus as UINT16.
459 // But it should de-facto always have a value that fits UINT8. To avoid
460 // unexpected behavior, verify value is in UINT8 bounds before casting)
461 //
462 ASSERT (Response->ScsiStatus <= MAX_UINT8);
463 Packet->TargetStatus = (UINT8)Response->ScsiStatus;
464
465 //
466 // Host adapter status and function return value depend on
467 // device response's host status
468 //
469 switch (Response->HostStatus) {
470 case PvScsiBtStatSuccess:
471 case PvScsiBtStatLinkedCommandCompleted:
472 case PvScsiBtStatLinkedCommandCompletedWithFlag:
473 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
474 return EFI_SUCCESS;
475
476 case PvScsiBtStatDataUnderrun:
477 //
478 // Report transferred amount in underrun
479 //
480 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
481 Packet->InTransferLength = (UINT32)Response->DataLen;
482 } else {
483 Packet->OutTransferLength = (UINT32)Response->DataLen;
484 }
485 Packet->HostAdapterStatus =
486 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
487 return EFI_SUCCESS;
488
489 case PvScsiBtStatDatarun:
490 Packet->HostAdapterStatus =
491 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
492 return EFI_SUCCESS;
493
494 case PvScsiBtStatSelTimeout:
495 Packet->HostAdapterStatus =
496 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
497 return EFI_TIMEOUT;
498
499 case PvScsiBtStatBusFree:
500 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE;
501 break;
502
503 case PvScsiBtStatInvPhase:
504 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
505 break;
506
507 case PvScsiBtStatSensFailed:
508 Packet->HostAdapterStatus =
509 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED;
510 break;
511
512 case PvScsiBtStatTagReject:
513 case PvScsiBtStatBadMsg:
514 Packet->HostAdapterStatus =
515 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT;
516 break;
517
518 case PvScsiBtStatBusReset:
519 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
520 break;
521
522 case PvScsiBtStatHaTimeout:
523 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
524 return EFI_TIMEOUT;
525
526 case PvScsiBtStatScsiParity:
527 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
528 break;
529
530 default:
531 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
532 break;
533 }
534
535 return EFI_DEVICE_ERROR;
536 }
537
538 /**
539 Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
540 EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
541 **/
542 STATIC
543 BOOLEAN
544 IsTargetInitialized (
545 IN UINT8 *Target
546 )
547 {
548 UINTN Idx;
549
550 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
551 if (Target[Idx] != 0xFF) {
552 return TRUE;
553 }
554 }
555 return FALSE;
556 }
557
558 //
559 // Ext SCSI Pass Thru
560 //
561
562 STATIC
563 EFI_STATUS
564 EFIAPI
565 PvScsiPassThru (
566 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
567 IN UINT8 *Target,
568 IN UINT64 Lun,
569 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
570 IN EFI_EVENT Event OPTIONAL
571 )
572 {
573 PVSCSI_DEV *Dev;
574 EFI_STATUS Status;
575 PVSCSI_RING_REQ_DESC *Request;
576 PVSCSI_RING_CMP_DESC *Response;
577
578 Dev = PVSCSI_FROM_PASS_THRU (This);
579
580 if (PvScsiIsReqRingFull (Dev)) {
581 return EFI_NOT_READY;
582 }
583
584 Request = PvScsiGetCurrentRequest (Dev);
585
586 Status = PopulateRequest (Dev, Target, Lun, Packet, Request);
587 if (EFI_ERROR (Status)) {
588 return Status;
589 }
590
591 //
592 // Writes to Request must be globally visible before making request
593 // available to device
594 //
595 MemoryFence ();
596 Dev->RingDesc.RingState->ReqProdIdx++;
597
598 Status = PvScsiMmioWrite32 (Dev, PvScsiRegOffsetKickRwIo, 0);
599 if (EFI_ERROR (Status)) {
600 //
601 // If kicking the host fails, we must fake a host adapter error.
602 // EFI_NOT_READY would save us the effort, but it would also suggest that
603 // the caller retry.
604 //
605 return ReportHostAdapterError (Packet);
606 }
607
608 Status = PvScsiWaitForRequestCompletion (Dev);
609 if (EFI_ERROR (Status)) {
610 //
611 // If waiting for request completion fails, we must fake a host adapter
612 // error. EFI_NOT_READY would save us the effort, but it would also suggest
613 // that the caller retry.
614 //
615 return ReportHostAdapterError (Packet);
616 }
617
618 Response = PvScsiGetCurrentResponse (Dev);
619 Status = HandleResponse (Dev, Packet, Response);
620
621 //
622 // Reads from response must complete before releasing completion entry
623 // to device
624 //
625 MemoryFence ();
626 Dev->RingDesc.RingState->CmpConsIdx++;
627
628 return Status;
629 }
630
631 STATIC
632 EFI_STATUS
633 EFIAPI
634 PvScsiGetNextTargetLun (
635 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
636 IN OUT UINT8 **Target,
637 IN OUT UINT64 *Lun
638 )
639 {
640 UINT8 *TargetPtr;
641 UINT8 LastTarget;
642 PVSCSI_DEV *Dev;
643
644 if (Target == NULL) {
645 return EFI_INVALID_PARAMETER;
646 }
647
648 //
649 // The Target input parameter is unnecessarily a pointer-to-pointer
650 //
651 TargetPtr = *Target;
652
653 //
654 // If target not initialized, return first target & LUN
655 //
656 if (!IsTargetInitialized (TargetPtr)) {
657 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
658 *Lun = 0;
659 return EFI_SUCCESS;
660 }
661
662 //
663 // We only use first byte of target identifer
664 //
665 LastTarget = *TargetPtr;
666
667 //
668 // Increment (target, LUN) pair if valid on input
669 //
670 Dev = PVSCSI_FROM_PASS_THRU (This);
671 if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {
672 return EFI_INVALID_PARAMETER;
673 }
674
675 if (*Lun < Dev->MaxLun) {
676 ++*Lun;
677 return EFI_SUCCESS;
678 }
679
680 if (LastTarget < Dev->MaxTarget) {
681 *Lun = 0;
682 ++LastTarget;
683 *TargetPtr = LastTarget;
684 return EFI_SUCCESS;
685 }
686
687 return EFI_NOT_FOUND;
688 }
689
690 STATIC
691 EFI_STATUS
692 EFIAPI
693 PvScsiBuildDevicePath (
694 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
695 IN UINT8 *Target,
696 IN UINT64 Lun,
697 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
698 )
699 {
700 UINT8 TargetValue;
701 PVSCSI_DEV *Dev;
702 SCSI_DEVICE_PATH *ScsiDevicePath;
703
704 if (DevicePath == NULL) {
705 return EFI_INVALID_PARAMETER;
706 }
707
708 //
709 // We only use first byte of target identifer
710 //
711 TargetValue = *Target;
712
713 Dev = PVSCSI_FROM_PASS_THRU (This);
714 if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun) {
715 return EFI_NOT_FOUND;
716 }
717
718 ScsiDevicePath = AllocatePool (sizeof (*ScsiDevicePath));
719 if (ScsiDevicePath == NULL) {
720 return EFI_OUT_OF_RESOURCES;
721 }
722
723 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
724 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
725 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
726 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
727 ScsiDevicePath->Pun = TargetValue;
728 ScsiDevicePath->Lun = (UINT16)Lun;
729
730 *DevicePath = &ScsiDevicePath->Header;
731 return EFI_SUCCESS;
732 }
733
734 STATIC
735 EFI_STATUS
736 EFIAPI
737 PvScsiGetTargetLun (
738 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
739 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
740 OUT UINT8 **Target,
741 OUT UINT64 *Lun
742 )
743 {
744 SCSI_DEVICE_PATH *ScsiDevicePath;
745 PVSCSI_DEV *Dev;
746
747 if (DevicePath == NULL || Target == NULL || *Target == NULL || Lun == NULL) {
748 return EFI_INVALID_PARAMETER;
749 }
750
751 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||
752 DevicePath->SubType != MSG_SCSI_DP) {
753 return EFI_UNSUPPORTED;
754 }
755
756 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
757 Dev = PVSCSI_FROM_PASS_THRU (This);
758 if (ScsiDevicePath->Pun > Dev->MaxTarget ||
759 ScsiDevicePath->Lun > Dev->MaxLun) {
760 return EFI_NOT_FOUND;
761 }
762
763 //
764 // We only use first byte of target identifer
765 //
766 **Target = (UINT8)ScsiDevicePath->Pun;
767 ZeroMem (*Target + 1, TARGET_MAX_BYTES - 1);
768 *Lun = ScsiDevicePath->Lun;
769
770 return EFI_SUCCESS;
771 }
772
773 STATIC
774 EFI_STATUS
775 EFIAPI
776 PvScsiResetChannel (
777 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
778 )
779 {
780 return EFI_UNSUPPORTED;
781 }
782
783 STATIC
784 EFI_STATUS
785 EFIAPI
786 PvScsiResetTargetLun (
787 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
788 IN UINT8 *Target,
789 IN UINT64 Lun
790 )
791 {
792 return EFI_UNSUPPORTED;
793 }
794
795 STATIC
796 EFI_STATUS
797 EFIAPI
798 PvScsiGetNextTarget (
799 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
800 IN OUT UINT8 **Target
801 )
802 {
803 UINT8 *TargetPtr;
804 UINT8 LastTarget;
805 PVSCSI_DEV *Dev;
806
807 if (Target == NULL) {
808 return EFI_INVALID_PARAMETER;
809 }
810
811 //
812 // The Target input parameter is unnecessarily a pointer-to-pointer
813 //
814 TargetPtr = *Target;
815
816 //
817 // If target not initialized, return first target
818 //
819 if (!IsTargetInitialized (TargetPtr)) {
820 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
821 return EFI_SUCCESS;
822 }
823
824 //
825 // We only use first byte of target identifer
826 //
827 LastTarget = *TargetPtr;
828
829 //
830 // Increment target if valid on input
831 //
832 Dev = PVSCSI_FROM_PASS_THRU (This);
833 if (LastTarget > Dev->MaxTarget) {
834 return EFI_INVALID_PARAMETER;
835 }
836
837 if (LastTarget < Dev->MaxTarget) {
838 ++LastTarget;
839 *TargetPtr = LastTarget;
840 return EFI_SUCCESS;
841 }
842
843 return EFI_NOT_FOUND;
844 }
845
846 STATIC
847 EFI_STATUS
848 PvScsiSetPciAttributes (
849 IN OUT PVSCSI_DEV *Dev
850 )
851 {
852 EFI_STATUS Status;
853
854 //
855 // Backup original PCI Attributes
856 //
857 Status = Dev->PciIo->Attributes (
858 Dev->PciIo,
859 EfiPciIoAttributeOperationGet,
860 0,
861 &Dev->OriginalPciAttributes
862 );
863 if (EFI_ERROR (Status)) {
864 return Status;
865 }
866
867 //
868 // Enable MMIO-Space & Bus-Mastering
869 //
870 Status = Dev->PciIo->Attributes (
871 Dev->PciIo,
872 EfiPciIoAttributeOperationEnable,
873 (EFI_PCI_IO_ATTRIBUTE_MEMORY |
874 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
875 NULL
876 );
877 if (EFI_ERROR (Status)) {
878 return Status;
879 }
880
881 //
882 // Signal device supports 64-bit DMA addresses
883 //
884 Status = Dev->PciIo->Attributes (
885 Dev->PciIo,
886 EfiPciIoAttributeOperationEnable,
887 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
888 NULL
889 );
890 if (EFI_ERROR (Status)) {
891 //
892 // Warn user that device will only be using 32-bit DMA addresses.
893 //
894 // Note that this does not prevent the device/driver from working
895 // and therefore we only warn and continue as usual.
896 //
897 DEBUG ((
898 DEBUG_WARN,
899 "%a: failed to enable 64-bit DMA addresses\n",
900 __FUNCTION__
901 ));
902 }
903
904 return EFI_SUCCESS;
905 }
906
907 STATIC
908 VOID
909 PvScsiRestorePciAttributes (
910 IN PVSCSI_DEV *Dev
911 )
912 {
913 Dev->PciIo->Attributes (
914 Dev->PciIo,
915 EfiPciIoAttributeOperationSet,
916 Dev->OriginalPciAttributes,
917 NULL
918 );
919 }
920
921 STATIC
922 EFI_STATUS
923 PvScsiAllocateSharedPages (
924 IN PVSCSI_DEV *Dev,
925 IN UINTN Pages,
926 OUT VOID **HostAddress,
927 OUT PVSCSI_DMA_DESC *DmaDesc
928 )
929 {
930 EFI_STATUS Status;
931 UINTN NumberOfBytes;
932
933 Status = Dev->PciIo->AllocateBuffer (
934 Dev->PciIo,
935 AllocateAnyPages,
936 EfiBootServicesData,
937 Pages,
938 HostAddress,
939 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
940 );
941 if (EFI_ERROR (Status)) {
942 return Status;
943 }
944
945 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
946 Status = Dev->PciIo->Map (
947 Dev->PciIo,
948 EfiPciIoOperationBusMasterCommonBuffer,
949 *HostAddress,
950 &NumberOfBytes,
951 &DmaDesc->DeviceAddress,
952 &DmaDesc->Mapping
953 );
954 if (EFI_ERROR (Status)) {
955 goto FreeBuffer;
956 }
957
958 if (NumberOfBytes != EFI_PAGES_TO_SIZE (Pages)) {
959 Status = EFI_OUT_OF_RESOURCES;
960 goto Unmap;
961 }
962
963 return EFI_SUCCESS;
964
965 Unmap:
966 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
967
968 FreeBuffer:
969 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, *HostAddress);
970
971 return Status;
972 }
973
974 STATIC
975 VOID
976 PvScsiFreeSharedPages (
977 IN PVSCSI_DEV *Dev,
978 IN UINTN Pages,
979 IN VOID *HostAddress,
980 IN PVSCSI_DMA_DESC *DmaDesc
981 )
982 {
983 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
984 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, HostAddress);
985 }
986
987 STATIC
988 EFI_STATUS
989 PvScsiInitRings (
990 IN OUT PVSCSI_DEV *Dev
991 )
992 {
993 EFI_STATUS Status;
994 union {
995 PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
996 UINT32 Uint32;
997 } AlignedCmd;
998 PVSCSI_CMD_DESC_SETUP_RINGS *Cmd;
999
1000 Cmd = &AlignedCmd.Cmd;
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 ZeroMem (Dev->RingDesc.RingState, EFI_PAGE_SIZE);
1012
1013 Status = PvScsiAllocateSharedPages (
1014 Dev,
1015 1,
1016 (VOID **)&Dev->RingDesc.RingReqs,
1017 &Dev->RingDesc.RingReqsDmaDesc
1018 );
1019 if (EFI_ERROR (Status)) {
1020 goto FreeRingState;
1021 }
1022 ZeroMem (Dev->RingDesc.RingReqs, EFI_PAGE_SIZE);
1023
1024 Status = PvScsiAllocateSharedPages (
1025 Dev,
1026 1,
1027 (VOID **)&Dev->RingDesc.RingCmps,
1028 &Dev->RingDesc.RingCmpsDmaDesc
1029 );
1030 if (EFI_ERROR (Status)) {
1031 goto FreeRingReqs;
1032 }
1033 ZeroMem (Dev->RingDesc.RingCmps, EFI_PAGE_SIZE);
1034
1035 ZeroMem (Cmd, sizeof (*Cmd));
1036 Cmd->ReqRingNumPages = 1;
1037 Cmd->CmpRingNumPages = 1;
1038 Cmd->RingsStatePPN = RShiftU64 (
1039 Dev->RingDesc.RingStateDmaDesc.DeviceAddress,
1040 EFI_PAGE_SHIFT
1041 );
1042 Cmd->ReqRingPPNs[0] = RShiftU64 (
1043 Dev->RingDesc.RingReqsDmaDesc.DeviceAddress,
1044 EFI_PAGE_SHIFT
1045 );
1046 Cmd->CmpRingPPNs[0] = RShiftU64 (
1047 Dev->RingDesc.RingCmpsDmaDesc.DeviceAddress,
1048 EFI_PAGE_SHIFT
1049 );
1050
1051 STATIC_ASSERT (
1052 sizeof (*Cmd) % sizeof (UINT32) == 0,
1053 "Cmd must be multiple of 32-bit words"
1054 );
1055 Status = PvScsiWriteCmdDesc (
1056 Dev,
1057 PvScsiCmdSetupRings,
1058 (UINT32 *)Cmd,
1059 sizeof (*Cmd) / sizeof (UINT32)
1060 );
1061 if (EFI_ERROR (Status)) {
1062 goto FreeRingCmps;
1063 }
1064
1065 return EFI_SUCCESS;
1066
1067 FreeRingCmps:
1068 PvScsiFreeSharedPages (
1069 Dev,
1070 1,
1071 Dev->RingDesc.RingCmps,
1072 &Dev->RingDesc.RingCmpsDmaDesc
1073 );
1074
1075 FreeRingReqs:
1076 PvScsiFreeSharedPages (
1077 Dev,
1078 1,
1079 Dev->RingDesc.RingReqs,
1080 &Dev->RingDesc.RingReqsDmaDesc
1081 );
1082
1083 FreeRingState:
1084 PvScsiFreeSharedPages (
1085 Dev,
1086 1,
1087 Dev->RingDesc.RingState,
1088 &Dev->RingDesc.RingStateDmaDesc
1089 );
1090
1091 return Status;
1092 }
1093
1094 STATIC
1095 VOID
1096 PvScsiFreeRings (
1097 IN OUT PVSCSI_DEV *Dev
1098 )
1099 {
1100 PvScsiFreeSharedPages (
1101 Dev,
1102 1,
1103 Dev->RingDesc.RingCmps,
1104 &Dev->RingDesc.RingCmpsDmaDesc
1105 );
1106
1107 PvScsiFreeSharedPages (
1108 Dev,
1109 1,
1110 Dev->RingDesc.RingReqs,
1111 &Dev->RingDesc.RingReqsDmaDesc
1112 );
1113
1114 PvScsiFreeSharedPages (
1115 Dev,
1116 1,
1117 Dev->RingDesc.RingState,
1118 &Dev->RingDesc.RingStateDmaDesc
1119 );
1120 }
1121
1122 STATIC
1123 EFI_STATUS
1124 PvScsiInit (
1125 IN OUT PVSCSI_DEV *Dev
1126 )
1127 {
1128 EFI_STATUS Status;
1129
1130 //
1131 // Init configuration
1132 //
1133 Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
1134 Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
1135 Dev->WaitForCmpStallInUsecs = PcdGet32 (PcdPvScsiWaitForCmpStallInUsecs);
1136
1137 //
1138 // Set PCI Attributes
1139 //
1140 Status = PvScsiSetPciAttributes (Dev);
1141 if (EFI_ERROR (Status)) {
1142 return Status;
1143 }
1144
1145 //
1146 // Reset adapter
1147 //
1148 Status = PvScsiResetAdapter (Dev);
1149 if (EFI_ERROR (Status)) {
1150 goto RestorePciAttributes;
1151 }
1152
1153 //
1154 // Init PVSCSI rings
1155 //
1156 Status = PvScsiInitRings (Dev);
1157 if (EFI_ERROR (Status)) {
1158 goto RestorePciAttributes;
1159 }
1160
1161 //
1162 // Allocate DMA communication buffer
1163 //
1164 Status = PvScsiAllocateSharedPages (
1165 Dev,
1166 EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
1167 (VOID **)&Dev->DmaBuf,
1168 &Dev->DmaBufDmaDesc
1169 );
1170 if (EFI_ERROR (Status)) {
1171 goto FreeRings;
1172 }
1173
1174 //
1175 // Populate the exported interface's attributes
1176 //
1177 Dev->PassThru.Mode = &Dev->PassThruMode;
1178 Dev->PassThru.PassThru = &PvScsiPassThru;
1179 Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
1180 Dev->PassThru.BuildDevicePath = &PvScsiBuildDevicePath;
1181 Dev->PassThru.GetTargetLun = &PvScsiGetTargetLun;
1182 Dev->PassThru.ResetChannel = &PvScsiResetChannel;
1183 Dev->PassThru.ResetTargetLun = &PvScsiResetTargetLun;
1184 Dev->PassThru.GetNextTarget = &PvScsiGetNextTarget;
1185
1186 //
1187 // AdapterId is a target for which no handle will be created during bus scan.
1188 // Prevent any conflict with real devices.
1189 //
1190 Dev->PassThruMode.AdapterId = MAX_UINT32;
1191
1192 //
1193 // Set both physical and logical attributes for non-RAID SCSI channel
1194 //
1195 Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
1196 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
1197
1198 //
1199 // No restriction on transfer buffer alignment
1200 //
1201 Dev->PassThruMode.IoAlign = 0;
1202
1203 return EFI_SUCCESS;
1204
1205 FreeRings:
1206 //
1207 // Reset device to stop device usage of the rings.
1208 // This is required to safely free the rings.
1209 //
1210 PvScsiResetAdapter (Dev);
1211
1212 PvScsiFreeRings (Dev);
1213
1214 RestorePciAttributes:
1215 PvScsiRestorePciAttributes (Dev);
1216
1217 return Status;
1218 }
1219
1220 STATIC
1221 VOID
1222 PvScsiUninit (
1223 IN OUT PVSCSI_DEV *Dev
1224 )
1225 {
1226 //
1227 // Reset device to:
1228 // - Make device stop processing all requests.
1229 // - Stop device usage of the rings.
1230 //
1231 // This is required to safely free the DMA communication buffer
1232 // and the rings.
1233 //
1234 PvScsiResetAdapter (Dev);
1235
1236 //
1237 // Free DMA communication buffer
1238 //
1239 PvScsiFreeSharedPages (
1240 Dev,
1241 EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
1242 Dev->DmaBuf,
1243 &Dev->DmaBufDmaDesc
1244 );
1245
1246 PvScsiFreeRings (Dev);
1247
1248 PvScsiRestorePciAttributes (Dev);
1249 }
1250
1251 /**
1252 Event notification called by ExitBootServices()
1253 **/
1254 STATIC
1255 VOID
1256 EFIAPI
1257 PvScsiExitBoot (
1258 IN EFI_EVENT Event,
1259 IN VOID *Context
1260 )
1261 {
1262 PVSCSI_DEV *Dev;
1263
1264 Dev = Context;
1265 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
1266
1267 //
1268 // Reset the device to stop device usage of the rings.
1269 //
1270 // We allocated said rings in EfiBootServicesData type memory, and code
1271 // executing after ExitBootServices() is permitted to overwrite it.
1272 //
1273 PvScsiResetAdapter (Dev);
1274 }
1275
1276 //
1277 // Driver Binding
1278 //
1279
1280 STATIC
1281 EFI_STATUS
1282 EFIAPI
1283 PvScsiDriverBindingSupported (
1284 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1285 IN EFI_HANDLE ControllerHandle,
1286 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1287 )
1288 {
1289 EFI_STATUS Status;
1290 EFI_PCI_IO_PROTOCOL *PciIo;
1291 PCI_TYPE00 Pci;
1292
1293 Status = gBS->OpenProtocol (
1294 ControllerHandle,
1295 &gEfiPciIoProtocolGuid,
1296 (VOID **)&PciIo,
1297 This->DriverBindingHandle,
1298 ControllerHandle,
1299 EFI_OPEN_PROTOCOL_BY_DRIVER
1300 );
1301 if (EFI_ERROR (Status)) {
1302 return Status;
1303 }
1304
1305 Status = PciIo->Pci.Read (
1306 PciIo,
1307 EfiPciIoWidthUint32,
1308 0,
1309 sizeof (Pci) / sizeof (UINT32),
1310 &Pci
1311 );
1312 if (EFI_ERROR (Status)) {
1313 goto Done;
1314 }
1315
1316 if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||
1317 (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI)) {
1318 Status = EFI_UNSUPPORTED;
1319 goto Done;
1320 }
1321
1322 Status = EFI_SUCCESS;
1323
1324 Done:
1325 gBS->CloseProtocol (
1326 ControllerHandle,
1327 &gEfiPciIoProtocolGuid,
1328 This->DriverBindingHandle,
1329 ControllerHandle
1330 );
1331
1332 return Status;
1333 }
1334
1335 STATIC
1336 EFI_STATUS
1337 EFIAPI
1338 PvScsiDriverBindingStart (
1339 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1340 IN EFI_HANDLE ControllerHandle,
1341 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1342 )
1343 {
1344 PVSCSI_DEV *Dev;
1345 EFI_STATUS Status;
1346
1347 Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));
1348 if (Dev == NULL) {
1349 return EFI_OUT_OF_RESOURCES;
1350 }
1351
1352 Status = gBS->OpenProtocol (
1353 ControllerHandle,
1354 &gEfiPciIoProtocolGuid,
1355 (VOID **)&Dev->PciIo,
1356 This->DriverBindingHandle,
1357 ControllerHandle,
1358 EFI_OPEN_PROTOCOL_BY_DRIVER
1359 );
1360 if (EFI_ERROR (Status)) {
1361 goto FreePvScsi;
1362 }
1363
1364 Status = PvScsiInit (Dev);
1365 if (EFI_ERROR (Status)) {
1366 goto ClosePciIo;
1367 }
1368
1369 Status = gBS->CreateEvent (
1370 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1371 TPL_CALLBACK,
1372 &PvScsiExitBoot,
1373 Dev,
1374 &Dev->ExitBoot
1375 );
1376 if (EFI_ERROR (Status)) {
1377 goto UninitDev;
1378 }
1379
1380 //
1381 // Setup complete, attempt to export the driver instance's PassThru interface
1382 //
1383 Dev->Signature = PVSCSI_SIG;
1384 Status = gBS->InstallProtocolInterface (
1385 &ControllerHandle,
1386 &gEfiExtScsiPassThruProtocolGuid,
1387 EFI_NATIVE_INTERFACE,
1388 &Dev->PassThru
1389 );
1390 if (EFI_ERROR (Status)) {
1391 goto CloseExitBoot;
1392 }
1393
1394 return EFI_SUCCESS;
1395
1396 CloseExitBoot:
1397 gBS->CloseEvent (Dev->ExitBoot);
1398
1399 UninitDev:
1400 PvScsiUninit (Dev);
1401
1402 ClosePciIo:
1403 gBS->CloseProtocol (
1404 ControllerHandle,
1405 &gEfiPciIoProtocolGuid,
1406 This->DriverBindingHandle,
1407 ControllerHandle
1408 );
1409
1410 FreePvScsi:
1411 FreePool (Dev);
1412
1413 return Status;
1414 }
1415
1416 STATIC
1417 EFI_STATUS
1418 EFIAPI
1419 PvScsiDriverBindingStop (
1420 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1421 IN EFI_HANDLE ControllerHandle,
1422 IN UINTN NumberOfChildren,
1423 IN EFI_HANDLE *ChildHandleBuffer
1424 )
1425 {
1426 EFI_STATUS Status;
1427 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
1428 PVSCSI_DEV *Dev;
1429
1430 Status = gBS->OpenProtocol (
1431 ControllerHandle,
1432 &gEfiExtScsiPassThruProtocolGuid,
1433 (VOID **)&PassThru,
1434 This->DriverBindingHandle,
1435 ControllerHandle,
1436 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
1437 );
1438 if (EFI_ERROR (Status)) {
1439 return Status;
1440 }
1441
1442 Dev = PVSCSI_FROM_PASS_THRU (PassThru);
1443
1444 Status = gBS->UninstallProtocolInterface (
1445 ControllerHandle,
1446 &gEfiExtScsiPassThruProtocolGuid,
1447 &Dev->PassThru
1448 );
1449 if (EFI_ERROR (Status)) {
1450 return Status;
1451 }
1452
1453 gBS->CloseEvent (Dev->ExitBoot);
1454
1455 PvScsiUninit (Dev);
1456
1457 gBS->CloseProtocol (
1458 ControllerHandle,
1459 &gEfiPciIoProtocolGuid,
1460 This->DriverBindingHandle,
1461 ControllerHandle
1462 );
1463
1464 FreePool (Dev);
1465
1466 return EFI_SUCCESS;
1467 }
1468
1469 STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {
1470 &PvScsiDriverBindingSupported,
1471 &PvScsiDriverBindingStart,
1472 &PvScsiDriverBindingStop,
1473 PVSCSI_BINDING_VERSION,
1474 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
1475 NULL // DriverBindingHandle, filled as well
1476 };
1477
1478 //
1479 // Component Name
1480 //
1481
1482 STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1483 { "eng;en", L"PVSCSI Host Driver" },
1484 { NULL, NULL }
1485 };
1486
1487 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1488
1489 STATIC
1490 EFI_STATUS
1491 EFIAPI
1492 PvScsiGetDriverName (
1493 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1494 IN CHAR8 *Language,
1495 OUT CHAR16 **DriverName
1496 )
1497 {
1498 return LookupUnicodeString2 (
1499 Language,
1500 This->SupportedLanguages,
1501 mDriverNameTable,
1502 DriverName,
1503 (BOOLEAN)(This == &mComponentName) // Iso639Language
1504 );
1505 }
1506
1507 STATIC
1508 EFI_STATUS
1509 EFIAPI
1510 PvScsiGetDeviceName (
1511 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1512 IN EFI_HANDLE DeviceHandle,
1513 IN EFI_HANDLE ChildHandle,
1514 IN CHAR8 *Language,
1515 OUT CHAR16 **ControllerName
1516 )
1517 {
1518 return EFI_UNSUPPORTED;
1519 }
1520
1521 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1522 &PvScsiGetDriverName,
1523 &PvScsiGetDeviceName,
1524 "eng" // SupportedLanguages, ISO 639-2 language codes
1525 };
1526
1527 STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
1528 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &PvScsiGetDriverName,
1529 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PvScsiGetDeviceName,
1530 "en" // SupportedLanguages, RFC 4646 language codes
1531 };
1532
1533 //
1534 // Entry Point
1535 //
1536
1537 EFI_STATUS
1538 EFIAPI
1539 PvScsiEntryPoint (
1540 IN EFI_HANDLE ImageHandle,
1541 IN EFI_SYSTEM_TABLE *SystemTable
1542 )
1543 {
1544 return EfiLibInstallDriverBindingComponentName2 (
1545 ImageHandle,
1546 SystemTable,
1547 &mPvScsiDriverBinding,
1548 ImageHandle,
1549 &mComponentName,
1550 &mComponentName2
1551 );
1552 }