]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PvScsiDxe/PvScsi.c
OvmfPkg/PvScsiDxe: Setup requests and completions rings
[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 Writes a 32-bit value into BAR0 using MMIO
37 **/
38 STATIC
39 EFI_STATUS
40 PvScsiMmioWrite32 (
41 IN CONST PVSCSI_DEV *Dev,
42 IN UINT64 Offset,
43 IN UINT32 Value
44 )
45 {
46 return Dev->PciIo->Mem.Write (
47 Dev->PciIo,
48 EfiPciIoWidthUint32,
49 PCI_BAR_IDX0,
50 Offset,
51 1, // Count
52 &Value
53 );
54 }
55
56 /**
57 Writes multiple words of data into BAR0 using MMIO
58 **/
59 STATIC
60 EFI_STATUS
61 PvScsiMmioWrite32Multiple (
62 IN CONST PVSCSI_DEV *Dev,
63 IN UINT64 Offset,
64 IN UINTN Count,
65 IN UINT32 *Words
66 )
67 {
68 return Dev->PciIo->Mem.Write (
69 Dev->PciIo,
70 EfiPciIoWidthFifoUint32,
71 PCI_BAR_IDX0,
72 Offset,
73 Count,
74 Words
75 );
76 }
77
78 /**
79 Send a PVSCSI command to device.
80
81 @param[in] Dev The pvscsi host device.
82 @param[in] Cmd The command to send to device.
83 @param[in] OPTIONAL DescWords An optional command descriptor (If command
84 have a descriptor). The descriptor is
85 provided as an array of UINT32 words and
86 is must be 32-bit aligned.
87 @param[in] DescWordsCount The number of words in command descriptor.
88 Caller must specify here 0 if DescWords
89 is not supplied (It is optional). In that
90 case, DescWords is ignored.
91
92 @return Status codes returned by Dev->PciIo->Mem.Write().
93
94 **/
95 STATIC
96 EFI_STATUS
97 PvScsiWriteCmdDesc (
98 IN CONST PVSCSI_DEV *Dev,
99 IN UINT32 Cmd,
100 IN UINT32 *DescWords OPTIONAL,
101 IN UINTN DescWordsCount
102 )
103 {
104 EFI_STATUS Status;
105
106 if (DescWordsCount > PVSCSI_MAX_CMD_DATA_WORDS) {
107 return EFI_INVALID_PARAMETER;
108 }
109
110 Status = PvScsiMmioWrite32 (Dev, PvScsiRegOffsetCommand, Cmd);
111 if (EFI_ERROR (Status)) {
112 return Status;
113 }
114
115 if (DescWordsCount > 0) {
116 return PvScsiMmioWrite32Multiple (
117 Dev,
118 PvScsiRegOffsetCommandData,
119 DescWordsCount,
120 DescWords
121 );
122 }
123
124 return EFI_SUCCESS;
125 }
126
127 STATIC
128 EFI_STATUS
129 PvScsiResetAdapter (
130 IN CONST PVSCSI_DEV *Dev
131 )
132 {
133 return PvScsiWriteCmdDesc (Dev, PvScsiCmdAdapterReset, NULL, 0);
134 }
135
136 /**
137 Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
138 EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
139 **/
140 STATIC
141 BOOLEAN
142 IsTargetInitialized (
143 IN UINT8 *Target
144 )
145 {
146 UINTN Idx;
147
148 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
149 if (Target[Idx] != 0xFF) {
150 return TRUE;
151 }
152 }
153 return FALSE;
154 }
155
156 //
157 // Ext SCSI Pass Thru
158 //
159
160 STATIC
161 EFI_STATUS
162 EFIAPI
163 PvScsiPassThru (
164 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
165 IN UINT8 *Target,
166 IN UINT64 Lun,
167 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
168 IN EFI_EVENT Event OPTIONAL
169 )
170 {
171 return EFI_UNSUPPORTED;
172 }
173
174 STATIC
175 EFI_STATUS
176 EFIAPI
177 PvScsiGetNextTargetLun (
178 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
179 IN OUT UINT8 **Target,
180 IN OUT UINT64 *Lun
181 )
182 {
183 UINT8 *TargetPtr;
184 UINT8 LastTarget;
185 PVSCSI_DEV *Dev;
186
187 if (Target == NULL) {
188 return EFI_INVALID_PARAMETER;
189 }
190
191 //
192 // The Target input parameter is unnecessarily a pointer-to-pointer
193 //
194 TargetPtr = *Target;
195
196 //
197 // If target not initialized, return first target & LUN
198 //
199 if (!IsTargetInitialized (TargetPtr)) {
200 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
201 *Lun = 0;
202 return EFI_SUCCESS;
203 }
204
205 //
206 // We only use first byte of target identifer
207 //
208 LastTarget = *TargetPtr;
209
210 //
211 // Increment (target, LUN) pair if valid on input
212 //
213 Dev = PVSCSI_FROM_PASS_THRU (This);
214 if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {
215 return EFI_INVALID_PARAMETER;
216 }
217
218 if (*Lun < Dev->MaxLun) {
219 ++*Lun;
220 return EFI_SUCCESS;
221 }
222
223 if (LastTarget < Dev->MaxTarget) {
224 *Lun = 0;
225 ++LastTarget;
226 *TargetPtr = LastTarget;
227 return EFI_SUCCESS;
228 }
229
230 return EFI_NOT_FOUND;
231 }
232
233 STATIC
234 EFI_STATUS
235 EFIAPI
236 PvScsiBuildDevicePath (
237 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
238 IN UINT8 *Target,
239 IN UINT64 Lun,
240 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
241 )
242 {
243 UINT8 TargetValue;
244 PVSCSI_DEV *Dev;
245 SCSI_DEVICE_PATH *ScsiDevicePath;
246
247 if (DevicePath == NULL) {
248 return EFI_INVALID_PARAMETER;
249 }
250
251 //
252 // We only use first byte of target identifer
253 //
254 TargetValue = *Target;
255
256 Dev = PVSCSI_FROM_PASS_THRU (This);
257 if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun) {
258 return EFI_NOT_FOUND;
259 }
260
261 ScsiDevicePath = AllocatePool (sizeof (*ScsiDevicePath));
262 if (ScsiDevicePath == NULL) {
263 return EFI_OUT_OF_RESOURCES;
264 }
265
266 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
267 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
268 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
269 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
270 ScsiDevicePath->Pun = TargetValue;
271 ScsiDevicePath->Lun = (UINT16)Lun;
272
273 *DevicePath = &ScsiDevicePath->Header;
274 return EFI_SUCCESS;
275 }
276
277 STATIC
278 EFI_STATUS
279 EFIAPI
280 PvScsiGetTargetLun (
281 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
282 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
283 OUT UINT8 **Target,
284 OUT UINT64 *Lun
285 )
286 {
287 SCSI_DEVICE_PATH *ScsiDevicePath;
288 PVSCSI_DEV *Dev;
289
290 if (DevicePath == NULL || Target == NULL || *Target == NULL || Lun == NULL) {
291 return EFI_INVALID_PARAMETER;
292 }
293
294 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||
295 DevicePath->SubType != MSG_SCSI_DP) {
296 return EFI_UNSUPPORTED;
297 }
298
299 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
300 Dev = PVSCSI_FROM_PASS_THRU (This);
301 if (ScsiDevicePath->Pun > Dev->MaxTarget ||
302 ScsiDevicePath->Lun > Dev->MaxLun) {
303 return EFI_NOT_FOUND;
304 }
305
306 //
307 // We only use first byte of target identifer
308 //
309 **Target = (UINT8)ScsiDevicePath->Pun;
310 ZeroMem (*Target + 1, TARGET_MAX_BYTES - 1);
311 *Lun = ScsiDevicePath->Lun;
312
313 return EFI_SUCCESS;
314 }
315
316 STATIC
317 EFI_STATUS
318 EFIAPI
319 PvScsiResetChannel (
320 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
321 )
322 {
323 return EFI_UNSUPPORTED;
324 }
325
326 STATIC
327 EFI_STATUS
328 EFIAPI
329 PvScsiResetTargetLun (
330 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
331 IN UINT8 *Target,
332 IN UINT64 Lun
333 )
334 {
335 return EFI_UNSUPPORTED;
336 }
337
338 STATIC
339 EFI_STATUS
340 EFIAPI
341 PvScsiGetNextTarget (
342 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
343 IN OUT UINT8 **Target
344 )
345 {
346 UINT8 *TargetPtr;
347 UINT8 LastTarget;
348 PVSCSI_DEV *Dev;
349
350 if (Target == NULL) {
351 return EFI_INVALID_PARAMETER;
352 }
353
354 //
355 // The Target input parameter is unnecessarily a pointer-to-pointer
356 //
357 TargetPtr = *Target;
358
359 //
360 // If target not initialized, return first target
361 //
362 if (!IsTargetInitialized (TargetPtr)) {
363 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
364 return EFI_SUCCESS;
365 }
366
367 //
368 // We only use first byte of target identifer
369 //
370 LastTarget = *TargetPtr;
371
372 //
373 // Increment target if valid on input
374 //
375 Dev = PVSCSI_FROM_PASS_THRU (This);
376 if (LastTarget > Dev->MaxTarget) {
377 return EFI_INVALID_PARAMETER;
378 }
379
380 if (LastTarget < Dev->MaxTarget) {
381 ++LastTarget;
382 *TargetPtr = LastTarget;
383 return EFI_SUCCESS;
384 }
385
386 return EFI_NOT_FOUND;
387 }
388
389 STATIC
390 EFI_STATUS
391 PvScsiSetPciAttributes (
392 IN OUT PVSCSI_DEV *Dev
393 )
394 {
395 EFI_STATUS Status;
396
397 //
398 // Backup original PCI Attributes
399 //
400 Status = Dev->PciIo->Attributes (
401 Dev->PciIo,
402 EfiPciIoAttributeOperationGet,
403 0,
404 &Dev->OriginalPciAttributes
405 );
406 if (EFI_ERROR (Status)) {
407 return Status;
408 }
409
410 //
411 // Enable MMIO-Space & Bus-Mastering
412 //
413 Status = Dev->PciIo->Attributes (
414 Dev->PciIo,
415 EfiPciIoAttributeOperationEnable,
416 (EFI_PCI_IO_ATTRIBUTE_MEMORY |
417 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
418 NULL
419 );
420 if (EFI_ERROR (Status)) {
421 return Status;
422 }
423
424 return EFI_SUCCESS;
425 }
426
427 STATIC
428 VOID
429 PvScsiRestorePciAttributes (
430 IN PVSCSI_DEV *Dev
431 )
432 {
433 Dev->PciIo->Attributes (
434 Dev->PciIo,
435 EfiPciIoAttributeOperationSet,
436 Dev->OriginalPciAttributes,
437 NULL
438 );
439 }
440
441 STATIC
442 EFI_STATUS
443 PvScsiAllocateSharedPages (
444 IN PVSCSI_DEV *Dev,
445 IN UINTN Pages,
446 OUT VOID **HostAddress,
447 OUT PVSCSI_DMA_DESC *DmaDesc
448 )
449 {
450 EFI_STATUS Status;
451 UINTN NumberOfBytes;
452
453 Status = Dev->PciIo->AllocateBuffer (
454 Dev->PciIo,
455 AllocateAnyPages,
456 EfiBootServicesData,
457 Pages,
458 HostAddress,
459 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
460 );
461 if (EFI_ERROR (Status)) {
462 return Status;
463 }
464
465 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
466 Status = Dev->PciIo->Map (
467 Dev->PciIo,
468 EfiPciIoOperationBusMasterCommonBuffer,
469 *HostAddress,
470 &NumberOfBytes,
471 &DmaDesc->DeviceAddress,
472 &DmaDesc->Mapping
473 );
474 if (EFI_ERROR (Status)) {
475 goto FreeBuffer;
476 }
477
478 if (NumberOfBytes != EFI_PAGES_TO_SIZE (Pages)) {
479 Status = EFI_OUT_OF_RESOURCES;
480 goto Unmap;
481 }
482
483 return EFI_SUCCESS;
484
485 Unmap:
486 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
487
488 FreeBuffer:
489 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, *HostAddress);
490
491 return Status;
492 }
493
494 STATIC
495 VOID
496 PvScsiFreeSharedPages (
497 IN PVSCSI_DEV *Dev,
498 IN UINTN Pages,
499 IN VOID *HostAddress,
500 IN PVSCSI_DMA_DESC *DmaDesc
501 )
502 {
503 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
504 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, HostAddress);
505 }
506
507 STATIC
508 EFI_STATUS
509 PvScsiInitRings (
510 IN OUT PVSCSI_DEV *Dev
511 )
512 {
513 EFI_STATUS Status;
514 union {
515 PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
516 UINT32 Uint32;
517 } AlignedCmd;
518 PVSCSI_CMD_DESC_SETUP_RINGS *Cmd;
519
520 Cmd = &AlignedCmd.Cmd;
521
522 Status = PvScsiAllocateSharedPages (
523 Dev,
524 1,
525 (VOID **)&Dev->RingDesc.RingState,
526 &Dev->RingDesc.RingStateDmaDesc
527 );
528 if (EFI_ERROR (Status)) {
529 return Status;
530 }
531 ZeroMem (Dev->RingDesc.RingState, EFI_PAGE_SIZE);
532
533 Status = PvScsiAllocateSharedPages (
534 Dev,
535 1,
536 (VOID **)&Dev->RingDesc.RingReqs,
537 &Dev->RingDesc.RingReqsDmaDesc
538 );
539 if (EFI_ERROR (Status)) {
540 goto FreeRingState;
541 }
542 ZeroMem (Dev->RingDesc.RingReqs, EFI_PAGE_SIZE);
543
544 Status = PvScsiAllocateSharedPages (
545 Dev,
546 1,
547 (VOID **)&Dev->RingDesc.RingCmps,
548 &Dev->RingDesc.RingCmpsDmaDesc
549 );
550 if (EFI_ERROR (Status)) {
551 goto FreeRingReqs;
552 }
553 ZeroMem (Dev->RingDesc.RingCmps, EFI_PAGE_SIZE);
554
555 ZeroMem (Cmd, sizeof (*Cmd));
556 Cmd->ReqRingNumPages = 1;
557 Cmd->CmpRingNumPages = 1;
558 Cmd->RingsStatePPN = RShiftU64 (
559 Dev->RingDesc.RingStateDmaDesc.DeviceAddress,
560 EFI_PAGE_SHIFT
561 );
562 Cmd->ReqRingPPNs[0] = RShiftU64 (
563 Dev->RingDesc.RingReqsDmaDesc.DeviceAddress,
564 EFI_PAGE_SHIFT
565 );
566 Cmd->CmpRingPPNs[0] = RShiftU64 (
567 Dev->RingDesc.RingCmpsDmaDesc.DeviceAddress,
568 EFI_PAGE_SHIFT
569 );
570
571 STATIC_ASSERT (
572 sizeof (*Cmd) % sizeof (UINT32) == 0,
573 "Cmd must be multiple of 32-bit words"
574 );
575 Status = PvScsiWriteCmdDesc (
576 Dev,
577 PvScsiCmdSetupRings,
578 (UINT32 *)Cmd,
579 sizeof (*Cmd) / sizeof (UINT32)
580 );
581 if (EFI_ERROR (Status)) {
582 goto FreeRingCmps;
583 }
584
585 return EFI_SUCCESS;
586
587 FreeRingCmps:
588 PvScsiFreeSharedPages (
589 Dev,
590 1,
591 Dev->RingDesc.RingCmps,
592 &Dev->RingDesc.RingCmpsDmaDesc
593 );
594
595 FreeRingReqs:
596 PvScsiFreeSharedPages (
597 Dev,
598 1,
599 Dev->RingDesc.RingReqs,
600 &Dev->RingDesc.RingReqsDmaDesc
601 );
602
603 FreeRingState:
604 PvScsiFreeSharedPages (
605 Dev,
606 1,
607 Dev->RingDesc.RingState,
608 &Dev->RingDesc.RingStateDmaDesc
609 );
610
611 return Status;
612 }
613
614 STATIC
615 VOID
616 PvScsiFreeRings (
617 IN OUT PVSCSI_DEV *Dev
618 )
619 {
620 PvScsiFreeSharedPages (
621 Dev,
622 1,
623 Dev->RingDesc.RingCmps,
624 &Dev->RingDesc.RingCmpsDmaDesc
625 );
626
627 PvScsiFreeSharedPages (
628 Dev,
629 1,
630 Dev->RingDesc.RingReqs,
631 &Dev->RingDesc.RingReqsDmaDesc
632 );
633
634 PvScsiFreeSharedPages (
635 Dev,
636 1,
637 Dev->RingDesc.RingState,
638 &Dev->RingDesc.RingStateDmaDesc
639 );
640 }
641
642 STATIC
643 EFI_STATUS
644 PvScsiInit (
645 IN OUT PVSCSI_DEV *Dev
646 )
647 {
648 EFI_STATUS Status;
649
650 //
651 // Init configuration
652 //
653 Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
654 Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
655
656 //
657 // Set PCI Attributes
658 //
659 Status = PvScsiSetPciAttributes (Dev);
660 if (EFI_ERROR (Status)) {
661 return Status;
662 }
663
664 //
665 // Reset adapter
666 //
667 Status = PvScsiResetAdapter (Dev);
668 if (EFI_ERROR (Status)) {
669 goto RestorePciAttributes;
670 }
671
672 //
673 // Init PVSCSI rings
674 //
675 Status = PvScsiInitRings (Dev);
676 if (EFI_ERROR (Status)) {
677 goto RestorePciAttributes;
678 }
679
680 //
681 // Populate the exported interface's attributes
682 //
683 Dev->PassThru.Mode = &Dev->PassThruMode;
684 Dev->PassThru.PassThru = &PvScsiPassThru;
685 Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
686 Dev->PassThru.BuildDevicePath = &PvScsiBuildDevicePath;
687 Dev->PassThru.GetTargetLun = &PvScsiGetTargetLun;
688 Dev->PassThru.ResetChannel = &PvScsiResetChannel;
689 Dev->PassThru.ResetTargetLun = &PvScsiResetTargetLun;
690 Dev->PassThru.GetNextTarget = &PvScsiGetNextTarget;
691
692 //
693 // AdapterId is a target for which no handle will be created during bus scan.
694 // Prevent any conflict with real devices.
695 //
696 Dev->PassThruMode.AdapterId = MAX_UINT32;
697
698 //
699 // Set both physical and logical attributes for non-RAID SCSI channel
700 //
701 Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
702 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
703
704 //
705 // No restriction on transfer buffer alignment
706 //
707 Dev->PassThruMode.IoAlign = 0;
708
709 return EFI_SUCCESS;
710
711 RestorePciAttributes:
712 PvScsiRestorePciAttributes (Dev);
713
714 return Status;
715 }
716
717 STATIC
718 VOID
719 PvScsiUninit (
720 IN OUT PVSCSI_DEV *Dev
721 )
722 {
723 //
724 // Reset device to stop device usage of the rings.
725 // This is required to safely free the rings.
726 //
727 PvScsiResetAdapter (Dev);
728
729 PvScsiFreeRings (Dev);
730
731 PvScsiRestorePciAttributes (Dev);
732 }
733
734 //
735 // Driver Binding
736 //
737
738 STATIC
739 EFI_STATUS
740 EFIAPI
741 PvScsiDriverBindingSupported (
742 IN EFI_DRIVER_BINDING_PROTOCOL *This,
743 IN EFI_HANDLE ControllerHandle,
744 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
745 )
746 {
747 EFI_STATUS Status;
748 EFI_PCI_IO_PROTOCOL *PciIo;
749 PCI_TYPE00 Pci;
750
751 Status = gBS->OpenProtocol (
752 ControllerHandle,
753 &gEfiPciIoProtocolGuid,
754 (VOID **)&PciIo,
755 This->DriverBindingHandle,
756 ControllerHandle,
757 EFI_OPEN_PROTOCOL_BY_DRIVER
758 );
759 if (EFI_ERROR (Status)) {
760 return Status;
761 }
762
763 Status = PciIo->Pci.Read (
764 PciIo,
765 EfiPciIoWidthUint32,
766 0,
767 sizeof (Pci) / sizeof (UINT32),
768 &Pci
769 );
770 if (EFI_ERROR (Status)) {
771 goto Done;
772 }
773
774 if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||
775 (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI)) {
776 Status = EFI_UNSUPPORTED;
777 goto Done;
778 }
779
780 Status = EFI_SUCCESS;
781
782 Done:
783 gBS->CloseProtocol (
784 ControllerHandle,
785 &gEfiPciIoProtocolGuid,
786 This->DriverBindingHandle,
787 ControllerHandle
788 );
789
790 return Status;
791 }
792
793 STATIC
794 EFI_STATUS
795 EFIAPI
796 PvScsiDriverBindingStart (
797 IN EFI_DRIVER_BINDING_PROTOCOL *This,
798 IN EFI_HANDLE ControllerHandle,
799 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
800 )
801 {
802 PVSCSI_DEV *Dev;
803 EFI_STATUS Status;
804
805 Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));
806 if (Dev == NULL) {
807 return EFI_OUT_OF_RESOURCES;
808 }
809
810 Status = gBS->OpenProtocol (
811 ControllerHandle,
812 &gEfiPciIoProtocolGuid,
813 (VOID **)&Dev->PciIo,
814 This->DriverBindingHandle,
815 ControllerHandle,
816 EFI_OPEN_PROTOCOL_BY_DRIVER
817 );
818 if (EFI_ERROR (Status)) {
819 goto FreePvScsi;
820 }
821
822 Status = PvScsiInit (Dev);
823 if (EFI_ERROR (Status)) {
824 goto ClosePciIo;
825 }
826
827 //
828 // Setup complete, attempt to export the driver instance's PassThru interface
829 //
830 Dev->Signature = PVSCSI_SIG;
831 Status = gBS->InstallProtocolInterface (
832 &ControllerHandle,
833 &gEfiExtScsiPassThruProtocolGuid,
834 EFI_NATIVE_INTERFACE,
835 &Dev->PassThru
836 );
837 if (EFI_ERROR (Status)) {
838 goto UninitDev;
839 }
840
841 return EFI_SUCCESS;
842
843 UninitDev:
844 PvScsiUninit (Dev);
845
846 ClosePciIo:
847 gBS->CloseProtocol (
848 ControllerHandle,
849 &gEfiPciIoProtocolGuid,
850 This->DriverBindingHandle,
851 ControllerHandle
852 );
853
854 FreePvScsi:
855 FreePool (Dev);
856
857 return Status;
858 }
859
860 STATIC
861 EFI_STATUS
862 EFIAPI
863 PvScsiDriverBindingStop (
864 IN EFI_DRIVER_BINDING_PROTOCOL *This,
865 IN EFI_HANDLE ControllerHandle,
866 IN UINTN NumberOfChildren,
867 IN EFI_HANDLE *ChildHandleBuffer
868 )
869 {
870 EFI_STATUS Status;
871 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
872 PVSCSI_DEV *Dev;
873
874 Status = gBS->OpenProtocol (
875 ControllerHandle,
876 &gEfiExtScsiPassThruProtocolGuid,
877 (VOID **)&PassThru,
878 This->DriverBindingHandle,
879 ControllerHandle,
880 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
881 );
882 if (EFI_ERROR (Status)) {
883 return Status;
884 }
885
886 Dev = PVSCSI_FROM_PASS_THRU (PassThru);
887
888 Status = gBS->UninstallProtocolInterface (
889 ControllerHandle,
890 &gEfiExtScsiPassThruProtocolGuid,
891 &Dev->PassThru
892 );
893 if (EFI_ERROR (Status)) {
894 return Status;
895 }
896
897 PvScsiUninit (Dev);
898
899 gBS->CloseProtocol (
900 ControllerHandle,
901 &gEfiPciIoProtocolGuid,
902 This->DriverBindingHandle,
903 ControllerHandle
904 );
905
906 FreePool (Dev);
907
908 return EFI_SUCCESS;
909 }
910
911 STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {
912 &PvScsiDriverBindingSupported,
913 &PvScsiDriverBindingStart,
914 &PvScsiDriverBindingStop,
915 PVSCSI_BINDING_VERSION,
916 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
917 NULL // DriverBindingHandle, filled as well
918 };
919
920 //
921 // Component Name
922 //
923
924 STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
925 { "eng;en", L"PVSCSI Host Driver" },
926 { NULL, NULL }
927 };
928
929 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName;
930
931 STATIC
932 EFI_STATUS
933 EFIAPI
934 PvScsiGetDriverName (
935 IN EFI_COMPONENT_NAME_PROTOCOL *This,
936 IN CHAR8 *Language,
937 OUT CHAR16 **DriverName
938 )
939 {
940 return LookupUnicodeString2 (
941 Language,
942 This->SupportedLanguages,
943 mDriverNameTable,
944 DriverName,
945 (BOOLEAN)(This == &mComponentName) // Iso639Language
946 );
947 }
948
949 STATIC
950 EFI_STATUS
951 EFIAPI
952 PvScsiGetDeviceName (
953 IN EFI_COMPONENT_NAME_PROTOCOL *This,
954 IN EFI_HANDLE DeviceHandle,
955 IN EFI_HANDLE ChildHandle,
956 IN CHAR8 *Language,
957 OUT CHAR16 **ControllerName
958 )
959 {
960 return EFI_UNSUPPORTED;
961 }
962
963 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
964 &PvScsiGetDriverName,
965 &PvScsiGetDeviceName,
966 "eng" // SupportedLanguages, ISO 639-2 language codes
967 };
968
969 STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
970 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &PvScsiGetDriverName,
971 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PvScsiGetDeviceName,
972 "en" // SupportedLanguages, RFC 4646 language codes
973 };
974
975 //
976 // Entry Point
977 //
978
979 EFI_STATUS
980 EFIAPI
981 PvScsiEntryPoint (
982 IN EFI_HANDLE ImageHandle,
983 IN EFI_SYSTEM_TABLE *SystemTable
984 )
985 {
986 return EfiLibInstallDriverBindingComponentName2 (
987 ImageHandle,
988 SystemTable,
989 &mPvScsiDriverBinding,
990 ImageHandle,
991 &mComponentName,
992 &mComponentName2
993 );
994 }