]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PvScsiDxe/PvScsi.c
OvmfPkg/PvScsiDxe: Enable MMIO-Space & Bus-Mastering in PCI attributes
[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/BaseMemoryLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Library/UefiBootServicesTableLib.h>
17 #include <Library/UefiLib.h>
18 #include <Protocol/PciIo.h>
19 #include <Uefi/UefiSpec.h>
20
21 #include "PvScsi.h"
22
23 //
24 // Higher versions will be used before lower, 0x10-0xffffffef is the version
25 // range for IHV (Indie Hardware Vendors)
26 //
27 #define PVSCSI_BINDING_VERSION 0x10
28
29 //
30 // Ext SCSI Pass Thru utilities
31 //
32
33 /**
34 Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
35 EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
36 **/
37 STATIC
38 BOOLEAN
39 IsTargetInitialized (
40 IN UINT8 *Target
41 )
42 {
43 UINTN Idx;
44
45 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
46 if (Target[Idx] != 0xFF) {
47 return TRUE;
48 }
49 }
50 return FALSE;
51 }
52
53 //
54 // Ext SCSI Pass Thru
55 //
56
57 STATIC
58 EFI_STATUS
59 EFIAPI
60 PvScsiPassThru (
61 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
62 IN UINT8 *Target,
63 IN UINT64 Lun,
64 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
65 IN EFI_EVENT Event OPTIONAL
66 )
67 {
68 return EFI_UNSUPPORTED;
69 }
70
71 STATIC
72 EFI_STATUS
73 EFIAPI
74 PvScsiGetNextTargetLun (
75 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
76 IN OUT UINT8 **Target,
77 IN OUT UINT64 *Lun
78 )
79 {
80 UINT8 *TargetPtr;
81 UINT8 LastTarget;
82 PVSCSI_DEV *Dev;
83
84 if (Target == NULL) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 //
89 // The Target input parameter is unnecessarily a pointer-to-pointer
90 //
91 TargetPtr = *Target;
92
93 //
94 // If target not initialized, return first target & LUN
95 //
96 if (!IsTargetInitialized (TargetPtr)) {
97 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
98 *Lun = 0;
99 return EFI_SUCCESS;
100 }
101
102 //
103 // We only use first byte of target identifer
104 //
105 LastTarget = *TargetPtr;
106
107 //
108 // Increment (target, LUN) pair if valid on input
109 //
110 Dev = PVSCSI_FROM_PASS_THRU (This);
111 if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {
112 return EFI_INVALID_PARAMETER;
113 }
114
115 if (*Lun < Dev->MaxLun) {
116 ++*Lun;
117 return EFI_SUCCESS;
118 }
119
120 if (LastTarget < Dev->MaxTarget) {
121 *Lun = 0;
122 ++LastTarget;
123 *TargetPtr = LastTarget;
124 return EFI_SUCCESS;
125 }
126
127 return EFI_NOT_FOUND;
128 }
129
130 STATIC
131 EFI_STATUS
132 EFIAPI
133 PvScsiBuildDevicePath (
134 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
135 IN UINT8 *Target,
136 IN UINT64 Lun,
137 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
138 )
139 {
140 UINT8 TargetValue;
141 PVSCSI_DEV *Dev;
142 SCSI_DEVICE_PATH *ScsiDevicePath;
143
144 if (DevicePath == NULL) {
145 return EFI_INVALID_PARAMETER;
146 }
147
148 //
149 // We only use first byte of target identifer
150 //
151 TargetValue = *Target;
152
153 Dev = PVSCSI_FROM_PASS_THRU (This);
154 if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun) {
155 return EFI_NOT_FOUND;
156 }
157
158 ScsiDevicePath = AllocatePool (sizeof (*ScsiDevicePath));
159 if (ScsiDevicePath == NULL) {
160 return EFI_OUT_OF_RESOURCES;
161 }
162
163 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
164 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
165 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
166 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
167 ScsiDevicePath->Pun = TargetValue;
168 ScsiDevicePath->Lun = (UINT16)Lun;
169
170 *DevicePath = &ScsiDevicePath->Header;
171 return EFI_SUCCESS;
172 }
173
174 STATIC
175 EFI_STATUS
176 EFIAPI
177 PvScsiGetTargetLun (
178 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
179 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
180 OUT UINT8 **Target,
181 OUT UINT64 *Lun
182 )
183 {
184 SCSI_DEVICE_PATH *ScsiDevicePath;
185 PVSCSI_DEV *Dev;
186
187 if (DevicePath == NULL || Target == NULL || *Target == NULL || Lun == NULL) {
188 return EFI_INVALID_PARAMETER;
189 }
190
191 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||
192 DevicePath->SubType != MSG_SCSI_DP) {
193 return EFI_UNSUPPORTED;
194 }
195
196 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
197 Dev = PVSCSI_FROM_PASS_THRU (This);
198 if (ScsiDevicePath->Pun > Dev->MaxTarget ||
199 ScsiDevicePath->Lun > Dev->MaxLun) {
200 return EFI_NOT_FOUND;
201 }
202
203 //
204 // We only use first byte of target identifer
205 //
206 **Target = (UINT8)ScsiDevicePath->Pun;
207 ZeroMem (*Target + 1, TARGET_MAX_BYTES - 1);
208 *Lun = ScsiDevicePath->Lun;
209
210 return EFI_SUCCESS;
211 }
212
213 STATIC
214 EFI_STATUS
215 EFIAPI
216 PvScsiResetChannel (
217 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
218 )
219 {
220 return EFI_UNSUPPORTED;
221 }
222
223 STATIC
224 EFI_STATUS
225 EFIAPI
226 PvScsiResetTargetLun (
227 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
228 IN UINT8 *Target,
229 IN UINT64 Lun
230 )
231 {
232 return EFI_UNSUPPORTED;
233 }
234
235 STATIC
236 EFI_STATUS
237 EFIAPI
238 PvScsiGetNextTarget (
239 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
240 IN OUT UINT8 **Target
241 )
242 {
243 UINT8 *TargetPtr;
244 UINT8 LastTarget;
245 PVSCSI_DEV *Dev;
246
247 if (Target == NULL) {
248 return EFI_INVALID_PARAMETER;
249 }
250
251 //
252 // The Target input parameter is unnecessarily a pointer-to-pointer
253 //
254 TargetPtr = *Target;
255
256 //
257 // If target not initialized, return first target
258 //
259 if (!IsTargetInitialized (TargetPtr)) {
260 ZeroMem (TargetPtr, TARGET_MAX_BYTES);
261 return EFI_SUCCESS;
262 }
263
264 //
265 // We only use first byte of target identifer
266 //
267 LastTarget = *TargetPtr;
268
269 //
270 // Increment target if valid on input
271 //
272 Dev = PVSCSI_FROM_PASS_THRU (This);
273 if (LastTarget > Dev->MaxTarget) {
274 return EFI_INVALID_PARAMETER;
275 }
276
277 if (LastTarget < Dev->MaxTarget) {
278 ++LastTarget;
279 *TargetPtr = LastTarget;
280 return EFI_SUCCESS;
281 }
282
283 return EFI_NOT_FOUND;
284 }
285
286 STATIC
287 EFI_STATUS
288 PvScsiSetPciAttributes (
289 IN OUT PVSCSI_DEV *Dev
290 )
291 {
292 EFI_STATUS Status;
293
294 //
295 // Backup original PCI Attributes
296 //
297 Status = Dev->PciIo->Attributes (
298 Dev->PciIo,
299 EfiPciIoAttributeOperationGet,
300 0,
301 &Dev->OriginalPciAttributes
302 );
303 if (EFI_ERROR (Status)) {
304 return Status;
305 }
306
307 //
308 // Enable MMIO-Space & Bus-Mastering
309 //
310 Status = Dev->PciIo->Attributes (
311 Dev->PciIo,
312 EfiPciIoAttributeOperationEnable,
313 (EFI_PCI_IO_ATTRIBUTE_MEMORY |
314 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
315 NULL
316 );
317 if (EFI_ERROR (Status)) {
318 return Status;
319 }
320
321 return EFI_SUCCESS;
322 }
323
324 STATIC
325 VOID
326 PvScsiRestorePciAttributes (
327 IN PVSCSI_DEV *Dev
328 )
329 {
330 Dev->PciIo->Attributes (
331 Dev->PciIo,
332 EfiPciIoAttributeOperationSet,
333 Dev->OriginalPciAttributes,
334 NULL
335 );
336 }
337
338 STATIC
339 EFI_STATUS
340 PvScsiInit (
341 IN OUT PVSCSI_DEV *Dev
342 )
343 {
344 EFI_STATUS Status;
345
346 //
347 // Init configuration
348 //
349 Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
350 Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
351
352 //
353 // Set PCI Attributes
354 //
355 Status = PvScsiSetPciAttributes (Dev);
356 if (EFI_ERROR (Status)) {
357 return Status;
358 }
359
360 //
361 // Populate the exported interface's attributes
362 //
363 Dev->PassThru.Mode = &Dev->PassThruMode;
364 Dev->PassThru.PassThru = &PvScsiPassThru;
365 Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
366 Dev->PassThru.BuildDevicePath = &PvScsiBuildDevicePath;
367 Dev->PassThru.GetTargetLun = &PvScsiGetTargetLun;
368 Dev->PassThru.ResetChannel = &PvScsiResetChannel;
369 Dev->PassThru.ResetTargetLun = &PvScsiResetTargetLun;
370 Dev->PassThru.GetNextTarget = &PvScsiGetNextTarget;
371
372 //
373 // AdapterId is a target for which no handle will be created during bus scan.
374 // Prevent any conflict with real devices.
375 //
376 Dev->PassThruMode.AdapterId = MAX_UINT32;
377
378 //
379 // Set both physical and logical attributes for non-RAID SCSI channel
380 //
381 Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
382 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
383
384 //
385 // No restriction on transfer buffer alignment
386 //
387 Dev->PassThruMode.IoAlign = 0;
388
389 return EFI_SUCCESS;
390 }
391
392 STATIC
393 VOID
394 PvScsiUninit (
395 IN OUT PVSCSI_DEV *Dev
396 )
397 {
398 PvScsiRestorePciAttributes (Dev);
399 }
400
401 //
402 // Driver Binding
403 //
404
405 STATIC
406 EFI_STATUS
407 EFIAPI
408 PvScsiDriverBindingSupported (
409 IN EFI_DRIVER_BINDING_PROTOCOL *This,
410 IN EFI_HANDLE ControllerHandle,
411 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
412 )
413 {
414 EFI_STATUS Status;
415 EFI_PCI_IO_PROTOCOL *PciIo;
416 PCI_TYPE00 Pci;
417
418 Status = gBS->OpenProtocol (
419 ControllerHandle,
420 &gEfiPciIoProtocolGuid,
421 (VOID **)&PciIo,
422 This->DriverBindingHandle,
423 ControllerHandle,
424 EFI_OPEN_PROTOCOL_BY_DRIVER
425 );
426 if (EFI_ERROR (Status)) {
427 return Status;
428 }
429
430 Status = PciIo->Pci.Read (
431 PciIo,
432 EfiPciIoWidthUint32,
433 0,
434 sizeof (Pci) / sizeof (UINT32),
435 &Pci
436 );
437 if (EFI_ERROR (Status)) {
438 goto Done;
439 }
440
441 if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||
442 (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI)) {
443 Status = EFI_UNSUPPORTED;
444 goto Done;
445 }
446
447 Status = EFI_SUCCESS;
448
449 Done:
450 gBS->CloseProtocol (
451 ControllerHandle,
452 &gEfiPciIoProtocolGuid,
453 This->DriverBindingHandle,
454 ControllerHandle
455 );
456
457 return Status;
458 }
459
460 STATIC
461 EFI_STATUS
462 EFIAPI
463 PvScsiDriverBindingStart (
464 IN EFI_DRIVER_BINDING_PROTOCOL *This,
465 IN EFI_HANDLE ControllerHandle,
466 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
467 )
468 {
469 PVSCSI_DEV *Dev;
470 EFI_STATUS Status;
471
472 Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));
473 if (Dev == NULL) {
474 return EFI_OUT_OF_RESOURCES;
475 }
476
477 Status = gBS->OpenProtocol (
478 ControllerHandle,
479 &gEfiPciIoProtocolGuid,
480 (VOID **)&Dev->PciIo,
481 This->DriverBindingHandle,
482 ControllerHandle,
483 EFI_OPEN_PROTOCOL_BY_DRIVER
484 );
485 if (EFI_ERROR (Status)) {
486 goto FreePvScsi;
487 }
488
489 Status = PvScsiInit (Dev);
490 if (EFI_ERROR (Status)) {
491 goto ClosePciIo;
492 }
493
494 //
495 // Setup complete, attempt to export the driver instance's PassThru interface
496 //
497 Dev->Signature = PVSCSI_SIG;
498 Status = gBS->InstallProtocolInterface (
499 &ControllerHandle,
500 &gEfiExtScsiPassThruProtocolGuid,
501 EFI_NATIVE_INTERFACE,
502 &Dev->PassThru
503 );
504 if (EFI_ERROR (Status)) {
505 goto UninitDev;
506 }
507
508 return EFI_SUCCESS;
509
510 UninitDev:
511 PvScsiUninit (Dev);
512
513 ClosePciIo:
514 gBS->CloseProtocol (
515 ControllerHandle,
516 &gEfiPciIoProtocolGuid,
517 This->DriverBindingHandle,
518 ControllerHandle
519 );
520
521 FreePvScsi:
522 FreePool (Dev);
523
524 return Status;
525 }
526
527 STATIC
528 EFI_STATUS
529 EFIAPI
530 PvScsiDriverBindingStop (
531 IN EFI_DRIVER_BINDING_PROTOCOL *This,
532 IN EFI_HANDLE ControllerHandle,
533 IN UINTN NumberOfChildren,
534 IN EFI_HANDLE *ChildHandleBuffer
535 )
536 {
537 EFI_STATUS Status;
538 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
539 PVSCSI_DEV *Dev;
540
541 Status = gBS->OpenProtocol (
542 ControllerHandle,
543 &gEfiExtScsiPassThruProtocolGuid,
544 (VOID **)&PassThru,
545 This->DriverBindingHandle,
546 ControllerHandle,
547 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
548 );
549 if (EFI_ERROR (Status)) {
550 return Status;
551 }
552
553 Dev = PVSCSI_FROM_PASS_THRU (PassThru);
554
555 Status = gBS->UninstallProtocolInterface (
556 ControllerHandle,
557 &gEfiExtScsiPassThruProtocolGuid,
558 &Dev->PassThru
559 );
560 if (EFI_ERROR (Status)) {
561 return Status;
562 }
563
564 PvScsiUninit (Dev);
565
566 gBS->CloseProtocol (
567 ControllerHandle,
568 &gEfiPciIoProtocolGuid,
569 This->DriverBindingHandle,
570 ControllerHandle
571 );
572
573 FreePool (Dev);
574
575 return EFI_SUCCESS;
576 }
577
578 STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {
579 &PvScsiDriverBindingSupported,
580 &PvScsiDriverBindingStart,
581 &PvScsiDriverBindingStop,
582 PVSCSI_BINDING_VERSION,
583 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
584 NULL // DriverBindingHandle, filled as well
585 };
586
587 //
588 // Component Name
589 //
590
591 STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
592 { "eng;en", L"PVSCSI Host Driver" },
593 { NULL, NULL }
594 };
595
596 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName;
597
598 STATIC
599 EFI_STATUS
600 EFIAPI
601 PvScsiGetDriverName (
602 IN EFI_COMPONENT_NAME_PROTOCOL *This,
603 IN CHAR8 *Language,
604 OUT CHAR16 **DriverName
605 )
606 {
607 return LookupUnicodeString2 (
608 Language,
609 This->SupportedLanguages,
610 mDriverNameTable,
611 DriverName,
612 (BOOLEAN)(This == &mComponentName) // Iso639Language
613 );
614 }
615
616 STATIC
617 EFI_STATUS
618 EFIAPI
619 PvScsiGetDeviceName (
620 IN EFI_COMPONENT_NAME_PROTOCOL *This,
621 IN EFI_HANDLE DeviceHandle,
622 IN EFI_HANDLE ChildHandle,
623 IN CHAR8 *Language,
624 OUT CHAR16 **ControllerName
625 )
626 {
627 return EFI_UNSUPPORTED;
628 }
629
630 STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
631 &PvScsiGetDriverName,
632 &PvScsiGetDeviceName,
633 "eng" // SupportedLanguages, ISO 639-2 language codes
634 };
635
636 STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
637 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &PvScsiGetDriverName,
638 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PvScsiGetDeviceName,
639 "en" // SupportedLanguages, RFC 4646 language codes
640 };
641
642 //
643 // Entry Point
644 //
645
646 EFI_STATUS
647 EFIAPI
648 PvScsiEntryPoint (
649 IN EFI_HANDLE ImageHandle,
650 IN EFI_SYSTEM_TABLE *SystemTable
651 )
652 {
653 return EfiLibInstallDriverBindingComponentName2 (
654 ImageHandle,
655 SystemTable,
656 &mPvScsiDriverBinding,
657 ImageHandle,
658 &mComponentName,
659 &mComponentName2
660 );
661 }