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