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