]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PvScsiDxe/PvScsi.c
ShellPkg: Fix 'ping' command Ip4 receive flow.
[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 //
878 // Signal device supports 64-bit DMA addresses
879 //
880 Status = Dev->PciIo->Attributes (
881 Dev->PciIo,
882 EfiPciIoAttributeOperationEnable,
883 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
884 NULL
885 );
886 if (EFI_ERROR (Status)) {
887 //
888 // Warn user that device will only be using 32-bit DMA addresses.
889 //
890 // Note that this does not prevent the device/driver from working
891 // and therefore we only warn and continue as usual.
892 //
893 DEBUG ((
894 DEBUG_WARN,
895 "%a: failed to enable 64-bit DMA addresses\n",
896 __FUNCTION__
897 ));
898 }
899
900 return EFI_SUCCESS;
901 }
902
903 STATIC
904 VOID
905 PvScsiRestorePciAttributes (
906 IN PVSCSI_DEV *Dev
907 )
908 {
909 Dev->PciIo->Attributes (
910 Dev->PciIo,
911 EfiPciIoAttributeOperationSet,
912 Dev->OriginalPciAttributes,
913 NULL
914 );
915 }
916
917 STATIC
918 EFI_STATUS
919 PvScsiAllocateSharedPages (
920 IN PVSCSI_DEV *Dev,
921 IN UINTN Pages,
922 OUT VOID **HostAddress,
923 OUT PVSCSI_DMA_DESC *DmaDesc
924 )
925 {
926 EFI_STATUS Status;
927 UINTN NumberOfBytes;
928
929 Status = Dev->PciIo->AllocateBuffer (
930 Dev->PciIo,
931 AllocateAnyPages,
932 EfiBootServicesData,
933 Pages,
934 HostAddress,
935 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
936 );
937 if (EFI_ERROR (Status)) {
938 return Status;
939 }
940
941 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
942 Status = Dev->PciIo->Map (
943 Dev->PciIo,
944 EfiPciIoOperationBusMasterCommonBuffer,
945 *HostAddress,
946 &NumberOfBytes,
947 &DmaDesc->DeviceAddress,
948 &DmaDesc->Mapping
949 );
950 if (EFI_ERROR (Status)) {
951 goto FreeBuffer;
952 }
953
954 if (NumberOfBytes != EFI_PAGES_TO_SIZE (Pages)) {
955 Status = EFI_OUT_OF_RESOURCES;
956 goto Unmap;
957 }
958
959 return EFI_SUCCESS;
960
961 Unmap:
962 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
963
964 FreeBuffer:
965 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, *HostAddress);
966
967 return Status;
968 }
969
970 STATIC
971 VOID
972 PvScsiFreeSharedPages (
973 IN PVSCSI_DEV *Dev,
974 IN UINTN Pages,
975 IN VOID *HostAddress,
976 IN PVSCSI_DMA_DESC *DmaDesc
977 )
978 {
979 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
980 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, HostAddress);
981 }
982
983 STATIC
984 EFI_STATUS
985 PvScsiInitRings (
986 IN OUT PVSCSI_DEV *Dev
987 )
988 {
989 EFI_STATUS Status;
990 union {
991 PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
992 UINT32 Uint32;
993 } AlignedCmd;
994 PVSCSI_CMD_DESC_SETUP_RINGS *Cmd;
995
996 Cmd = &AlignedCmd.Cmd;
997
998 Status = PvScsiAllocateSharedPages (
999 Dev,
1000 1,
1001 (VOID **)&Dev->RingDesc.RingState,
1002 &Dev->RingDesc.RingStateDmaDesc
1003 );
1004 if (EFI_ERROR (Status)) {
1005 return Status;
1006 }
1007 ZeroMem (Dev->RingDesc.RingState, EFI_PAGE_SIZE);
1008
1009 Status = PvScsiAllocateSharedPages (
1010 Dev,
1011 1,
1012 (VOID **)&Dev->RingDesc.RingReqs,
1013 &Dev->RingDesc.RingReqsDmaDesc
1014 );
1015 if (EFI_ERROR (Status)) {
1016 goto FreeRingState;
1017 }
1018 ZeroMem (Dev->RingDesc.RingReqs, EFI_PAGE_SIZE);
1019
1020 Status = PvScsiAllocateSharedPages (
1021 Dev,
1022 1,
1023 (VOID **)&Dev->RingDesc.RingCmps,
1024 &Dev->RingDesc.RingCmpsDmaDesc
1025 );
1026 if (EFI_ERROR (Status)) {
1027 goto FreeRingReqs;
1028 }
1029 ZeroMem (Dev->RingDesc.RingCmps, EFI_PAGE_SIZE);
1030
1031 ZeroMem (Cmd, sizeof (*Cmd));
1032 Cmd->ReqRingNumPages = 1;
1033 Cmd->CmpRingNumPages = 1;
1034 Cmd->RingsStatePPN = RShiftU64 (
1035 Dev->RingDesc.RingStateDmaDesc.DeviceAddress,
1036 EFI_PAGE_SHIFT
1037 );
1038 Cmd->ReqRingPPNs[0] = RShiftU64 (
1039 Dev->RingDesc.RingReqsDmaDesc.DeviceAddress,
1040 EFI_PAGE_SHIFT
1041 );
1042 Cmd->CmpRingPPNs[0] = RShiftU64 (
1043 Dev->RingDesc.RingCmpsDmaDesc.DeviceAddress,
1044 EFI_PAGE_SHIFT
1045 );
1046
1047 STATIC_ASSERT (
1048 sizeof (*Cmd) % sizeof (UINT32) == 0,
1049 "Cmd must be multiple of 32-bit words"
1050 );
1051 Status = PvScsiWriteCmdDesc (
1052 Dev,
1053 PvScsiCmdSetupRings,
1054 (UINT32 *)Cmd,
1055 sizeof (*Cmd) / sizeof (UINT32)
1056 );
1057 if (EFI_ERROR (Status)) {
1058 goto FreeRingCmps;
1059 }
1060
1061 return EFI_SUCCESS;
1062
1063 FreeRingCmps:
1064 PvScsiFreeSharedPages (
1065 Dev,
1066 1,
1067 Dev->RingDesc.RingCmps,
1068 &Dev->RingDesc.RingCmpsDmaDesc
1069 );
1070
1071 FreeRingReqs:
1072 PvScsiFreeSharedPages (
1073 Dev,
1074 1,
1075 Dev->RingDesc.RingReqs,
1076 &Dev->RingDesc.RingReqsDmaDesc
1077 );
1078
1079 FreeRingState:
1080 PvScsiFreeSharedPages (
1081 Dev,
1082 1,
1083 Dev->RingDesc.RingState,
1084 &Dev->RingDesc.RingStateDmaDesc
1085 );
1086
1087 return Status;
1088 }
1089
1090 STATIC
1091 VOID
1092 PvScsiFreeRings (
1093 IN OUT PVSCSI_DEV *Dev
1094 )
1095 {
1096 PvScsiFreeSharedPages (
1097 Dev,
1098 1,
1099 Dev->RingDesc.RingCmps,
1100 &Dev->RingDesc.RingCmpsDmaDesc
1101 );
1102
1103 PvScsiFreeSharedPages (
1104 Dev,
1105 1,
1106 Dev->RingDesc.RingReqs,
1107 &Dev->RingDesc.RingReqsDmaDesc
1108 );
1109
1110 PvScsiFreeSharedPages (
1111 Dev,
1112 1,
1113 Dev->RingDesc.RingState,
1114 &Dev->RingDesc.RingStateDmaDesc
1115 );
1116 }
1117
1118 STATIC
1119 EFI_STATUS
1120 PvScsiInit (
1121 IN OUT PVSCSI_DEV *Dev
1122 )
1123 {
1124 EFI_STATUS Status;
1125
1126 //
1127 // Init configuration
1128 //
1129 Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
1130 Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
1131 Dev->WaitForCmpStallInUsecs = PcdGet32 (PcdPvScsiWaitForCmpStallInUsecs);
1132
1133 //
1134 // Set PCI Attributes
1135 //
1136 Status = PvScsiSetPciAttributes (Dev);
1137 if (EFI_ERROR (Status)) {
1138 return Status;
1139 }
1140
1141 //
1142 // Reset adapter
1143 //
1144 Status = PvScsiResetAdapter (Dev);
1145 if (EFI_ERROR (Status)) {
1146 goto RestorePciAttributes;
1147 }
1148
1149 //
1150 // Init PVSCSI rings
1151 //
1152 Status = PvScsiInitRings (Dev);
1153 if (EFI_ERROR (Status)) {
1154 goto RestorePciAttributes;
1155 }
1156
1157 //
1158 // Allocate DMA communication buffer
1159 //
1160 Status = PvScsiAllocateSharedPages (
1161 Dev,
1162 EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
1163 (VOID **)&Dev->DmaBuf,
1164 &Dev->DmaBufDmaDesc
1165 );
1166 if (EFI_ERROR (Status)) {
1167 goto FreeRings;
1168 }
1169
1170 //
1171 // Populate the exported interface's attributes
1172 //
1173 Dev->PassThru.Mode = &Dev->PassThruMode;
1174 Dev->PassThru.PassThru = &PvScsiPassThru;
1175 Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
1176 Dev->PassThru.BuildDevicePath = &PvScsiBuildDevicePath;
1177 Dev->PassThru.GetTargetLun = &PvScsiGetTargetLun;
1178 Dev->PassThru.ResetChannel = &PvScsiResetChannel;
1179 Dev->PassThru.ResetTargetLun = &PvScsiResetTargetLun;
1180 Dev->PassThru.GetNextTarget = &PvScsiGetNextTarget;
1181
1182 //
1183 // AdapterId is a target for which no handle will be created during bus scan.
1184 // Prevent any conflict with real devices.
1185 //
1186 Dev->PassThruMode.AdapterId = MAX_UINT32;
1187
1188 //
1189 // Set both physical and logical attributes for non-RAID SCSI channel
1190 //
1191 Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
1192 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
1193
1194 //
1195 // No restriction on transfer buffer alignment
1196 //
1197 Dev->PassThruMode.IoAlign = 0;
1198
1199 return EFI_SUCCESS;
1200
1201 FreeRings:
1202 //
1203 // Reset device to stop device usage of the rings.
1204 // This is required to safely free the rings.
1205 //
1206 PvScsiResetAdapter (Dev);
1207
1208 PvScsiFreeRings (Dev);
1209
1210 RestorePciAttributes:
1211 PvScsiRestorePciAttributes (Dev);
1212
1213 return Status;
1214 }
1215
1216 STATIC
1217 VOID
1218 PvScsiUninit (
1219 IN OUT PVSCSI_DEV *Dev
1220 )
1221 {
1222 //
1223 // Reset device to:
1224 // - Make device stop processing all requests.
1225 // - Stop device usage of the rings.
1226 //
1227 // This is required to safely free the DMA communication buffer
1228 // and the rings.
1229 //
1230 PvScsiResetAdapter (Dev);
1231
1232 //
1233 // Free DMA communication buffer
1234 //
1235 PvScsiFreeSharedPages (
1236 Dev,
1237 EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
1238 Dev->DmaBuf,
1239 &Dev->DmaBufDmaDesc
1240 );
1241
1242 PvScsiFreeRings (Dev);
1243
1244 PvScsiRestorePciAttributes (Dev);
1245 }
1246
1247 /**
1248 Event notification called by ExitBootServices()
1249 **/
1250 STATIC
1251 VOID
1252 EFIAPI
1253 PvScsiExitBoot (
1254 IN EFI_EVENT Event,
1255 IN VOID *Context
1256 )
1257 {
1258 PVSCSI_DEV *Dev;
1259
1260 Dev = Context;
1261 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
1262
1263 //
1264 // Reset the device to stop device usage of the rings.
1265 //
1266 // We allocated said rings in EfiBootServicesData type memory, and code
1267 // executing after ExitBootServices() is permitted to overwrite it.
1268 //
1269 PvScsiResetAdapter (Dev);
1270 }
1271
1272 //
1273 // Driver Binding
1274 //
1275
1276 STATIC
1277 EFI_STATUS
1278 EFIAPI
1279 PvScsiDriverBindingSupported (
1280 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1281 IN EFI_HANDLE ControllerHandle,
1282 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1283 )
1284 {
1285 EFI_STATUS Status;
1286 EFI_PCI_IO_PROTOCOL *PciIo;
1287 PCI_TYPE00 Pci;
1288
1289 Status = gBS->OpenProtocol (
1290 ControllerHandle,
1291 &gEfiPciIoProtocolGuid,
1292 (VOID **)&PciIo,
1293 This->DriverBindingHandle,
1294 ControllerHandle,
1295 EFI_OPEN_PROTOCOL_BY_DRIVER
1296 );
1297 if (EFI_ERROR (Status)) {
1298 return Status;
1299 }
1300
1301 Status = PciIo->Pci.Read (
1302 PciIo,
1303 EfiPciIoWidthUint32,
1304 0,
1305 sizeof (Pci) / sizeof (UINT32),
1306 &Pci
1307 );
1308 if (EFI_ERROR (Status)) {
1309 goto Done;
1310 }
1311
1312 if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||
1313 (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI)) {
1314 Status = EFI_UNSUPPORTED;
1315 goto Done;
1316 }
1317
1318 Status = EFI_SUCCESS;
1319
1320 Done:
1321 gBS->CloseProtocol (
1322 ControllerHandle,
1323 &gEfiPciIoProtocolGuid,
1324 This->DriverBindingHandle,
1325 ControllerHandle
1326 );
1327
1328 return Status;
1329 }
1330
1331 STATIC
1332 EFI_STATUS
1333 EFIAPI
1334 PvScsiDriverBindingStart (
1335 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1336 IN EFI_HANDLE ControllerHandle,
1337 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1338 )
1339 {
1340 PVSCSI_DEV *Dev;
1341 EFI_STATUS Status;
1342
1343 Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));
1344 if (Dev == NULL) {
1345 return EFI_OUT_OF_RESOURCES;
1346 }
1347
1348 Status = gBS->OpenProtocol (
1349 ControllerHandle,
1350 &gEfiPciIoProtocolGuid,
1351 (VOID **)&Dev->PciIo,
1352 This->DriverBindingHandle,
1353 ControllerHandle,
1354 EFI_OPEN_PROTOCOL_BY_DRIVER
1355 );
1356 if (EFI_ERROR (Status)) {
1357 goto FreePvScsi;
1358 }
1359
1360 Status = PvScsiInit (Dev);
1361 if (EFI_ERROR (Status)) {
1362 goto ClosePciIo;
1363 }
1364
1365 Status = gBS->CreateEvent (
1366 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1367 TPL_CALLBACK,
1368 &PvScsiExitBoot,
1369 Dev,
1370 &Dev->ExitBoot
1371 );
1372 if (EFI_ERROR (Status)) {
1373 goto UninitDev;
1374 }
1375
1376 //
1377 // Setup complete, attempt to export the driver instance's PassThru interface
1378 //
1379 Dev->Signature = PVSCSI_SIG;
1380 Status = gBS->InstallProtocolInterface (
1381 &ControllerHandle,
1382 &gEfiExtScsiPassThruProtocolGuid,
1383 EFI_NATIVE_INTERFACE,
1384 &Dev->PassThru
1385 );
1386 if (EFI_ERROR (Status)) {
1387 goto CloseExitBoot;
1388 }
1389
1390 return EFI_SUCCESS;
1391
1392 CloseExitBoot:
1393 gBS->CloseEvent (Dev->ExitBoot);
1394
1395 UninitDev:
1396 PvScsiUninit (Dev);
1397
1398 ClosePciIo:
1399 gBS->CloseProtocol (
1400 ControllerHandle,
1401 &gEfiPciIoProtocolGuid,
1402 This->DriverBindingHandle,
1403 ControllerHandle
1404 );
1405
1406 FreePvScsi:
1407 FreePool (Dev);
1408
1409 return Status;
1410 }
1411
1412 STATIC
1413 EFI_STATUS
1414 EFIAPI
1415 PvScsiDriverBindingStop (
1416 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1417 IN EFI_HANDLE ControllerHandle,
1418 IN UINTN NumberOfChildren,
1419 IN EFI_HANDLE *ChildHandleBuffer
1420 )
1421 {
1422 EFI_STATUS Status;
1423 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
1424 PVSCSI_DEV *Dev;
1425
1426 Status = gBS->OpenProtocol (
1427 ControllerHandle,
1428 &gEfiExtScsiPassThruProtocolGuid,
1429 (VOID **)&PassThru,
1430 This->DriverBindingHandle,
1431 ControllerHandle,
1432 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
1433 );
1434 if (EFI_ERROR (Status)) {
1435 return Status;
1436 }
1437
1438 Dev = PVSCSI_FROM_PASS_THRU (PassThru);
1439
1440 Status = gBS->UninstallProtocolInterface (
1441 ControllerHandle,
1442 &gEfiExtScsiPassThruProtocolGuid,
1443 &Dev->PassThru
1444 );
1445 if (EFI_ERROR (Status)) {
1446 return Status;
1447 }
1448
1449 gBS->CloseEvent (Dev->ExitBoot);
1450
1451 PvScsiUninit (Dev);
1452
1453 gBS->CloseProtocol (
1454 ControllerHandle,
1455 &gEfiPciIoProtocolGuid,
1456 This->DriverBindingHandle,
1457 ControllerHandle
1458 );
1459
1460 FreePool (Dev);
1461
1462 return EFI_SUCCESS;
1463 }
1464
1465 STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {
1466 &PvScsiDriverBindingSupported,
1467 &PvScsiDriverBindingStart,
1468 &PvScsiDriverBindingStop,
1469 PVSCSI_BINDING_VERSION,
1470 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
1471 NULL // DriverBindingHandle, filled as well
1472 };
1473
1474 //
1475 // Component Name
1476 //
1477
1478 STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1479 { "eng;en", L"PVSCSI Host Driver" },
1480 { NULL, NULL }
1481 };
1482
1483 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1484
1485 STATIC
1486 EFI_STATUS
1487 EFIAPI
1488 PvScsiGetDriverName (
1489 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1490 IN CHAR8 *Language,
1491 OUT CHAR16 **DriverName
1492 )
1493 {
1494 return LookupUnicodeString2 (
1495 Language,
1496 This->SupportedLanguages,
1497 mDriverNameTable,
1498 DriverName,
1499 (BOOLEAN)(This == &mComponentName) // Iso639Language
1500 );
1501 }
1502
1503 STATIC
1504 EFI_STATUS
1505 EFIAPI
1506 PvScsiGetDeviceName (
1507 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1508 IN EFI_HANDLE DeviceHandle,
1509 IN EFI_HANDLE ChildHandle,
1510 IN CHAR8 *Language,
1511 OUT CHAR16 **ControllerName
1512 )
1513 {
1514 return EFI_UNSUPPORTED;
1515 }
1516
1517 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1518 &PvScsiGetDriverName,
1519 &PvScsiGetDeviceName,
1520 "eng" // SupportedLanguages, ISO 639-2 language codes
1521 };
1522
1523 STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
1524 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &PvScsiGetDriverName,
1525 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PvScsiGetDeviceName,
1526 "en" // SupportedLanguages, RFC 4646 language codes
1527 };
1528
1529 //
1530 // Entry Point
1531 //
1532
1533 EFI_STATUS
1534 EFIAPI
1535 PvScsiEntryPoint (
1536 IN EFI_HANDLE ImageHandle,
1537 IN EFI_SYSTEM_TABLE *SystemTable
1538 )
1539 {
1540 return EfiLibInstallDriverBindingComponentName2 (
1541 ImageHandle,
1542 SystemTable,
1543 &mPvScsiDriverBinding,
1544 ImageHandle,
1545 &mComponentName,
1546 &mComponentName2
1547 );
1548 }