OvmfPkg/MptScsiDxe: Set and restore PCI attributes
[mirror_edk2.git] / OvmfPkg / MptScsiDxe / MptScsi.c
CommitLineData
feec20b2
NL
1/** @file\r
2\r
3 This driver produces Extended SCSI Pass Thru Protocol instances for\r
4 LSI Fusion MPT SCSI devices.\r
5\r
6 Copyright (C) 2020, Oracle and/or its affiliates.\r
7\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
f4707442
NL
12#include <IndustryStandard/FusionMptScsi.h>\r
13#include <IndustryStandard/Pci.h>\r
093cceaf 14#include <Library/BaseMemoryLib.h>\r
a53e5b41
NL
15#include <Library/DebugLib.h>\r
16#include <Library/MemoryAllocationLib.h>\r
093cceaf 17#include <Library/PcdLib.h>\r
f4707442 18#include <Library/UefiBootServicesTableLib.h>\r
ad8f2d6b 19#include <Library/UefiLib.h>\r
f4707442 20#include <Protocol/PciIo.h>\r
a53e5b41 21#include <Protocol/ScsiPassThruExt.h>\r
feec20b2
NL
22#include <Uefi/UefiSpec.h>\r
23\r
ad8f2d6b
NL
24//\r
25// Higher versions will be used before lower, 0x10-0xffffffef is the version\r
26// range for IVH (Indie Hardware Vendors)\r
27//\r
28#define MPT_SCSI_BINDING_VERSION 0x10\r
29\r
a53e5b41
NL
30//\r
31// Runtime Structures\r
32//\r
33\r
34#define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')\r
35typedef struct {\r
36 UINT32 Signature;\r
37 EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;\r
38 EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode;\r
093cceaf 39 UINT8 MaxTarget;\r
da8c0b8f 40 EFI_PCI_IO_PROTOCOL *PciIo;\r
ecdbdba6 41 UINT64 OriginalPciAttributes;\r
a53e5b41
NL
42} MPT_SCSI_DEV;\r
43\r
44#define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \\r
45 CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)\r
46\r
47//\r
48// Ext SCSI Pass Thru\r
49//\r
50\r
51STATIC\r
52EFI_STATUS\r
53EFIAPI\r
54MptScsiPassThru (\r
55 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
56 IN UINT8 *Target,\r
57 IN UINT64 Lun,\r
58 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
59 IN EFI_EVENT Event OPTIONAL\r
60 )\r
61{\r
62 return EFI_UNSUPPORTED;\r
63}\r
64\r
093cceaf
NL
65STATIC\r
66BOOLEAN\r
67IsTargetInitialized (\r
68 IN UINT8 *Target\r
69 )\r
70{\r
71 UINTN Idx;\r
72\r
73 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {\r
74 if (Target[Idx] != 0xFF) {\r
75 return TRUE;\r
76 }\r
77 }\r
78 return FALSE;\r
79}\r
80\r
a53e5b41
NL
81STATIC\r
82EFI_STATUS\r
83EFIAPI\r
84MptScsiGetNextTargetLun (\r
85 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
86 IN OUT UINT8 **Target,\r
87 IN OUT UINT64 *Lun\r
88 )\r
89{\r
093cceaf
NL
90 MPT_SCSI_DEV *Dev;\r
91\r
92 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
93 //\r
94 // Currently support only LUN 0, so hardcode it\r
95 //\r
96 if (!IsTargetInitialized (*Target)) {\r
97 ZeroMem (*Target, TARGET_MAX_BYTES);\r
98 *Lun = 0;\r
99 } else if (**Target > Dev->MaxTarget || *Lun > 0) {\r
100 return EFI_INVALID_PARAMETER;\r
101 } else if (**Target < Dev->MaxTarget) {\r
102 //\r
103 // This device interface support 256 targets only, so it's enough to\r
104 // increment the LSB of Target, as it will never overflow.\r
105 //\r
106 **Target += 1;\r
107 } else {\r
108 return EFI_NOT_FOUND;\r
109 }\r
110\r
111 return EFI_SUCCESS;\r
a53e5b41
NL
112}\r
113\r
114STATIC\r
115EFI_STATUS\r
116EFIAPI\r
117MptScsiGetNextTarget (\r
118 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
119 IN OUT UINT8 **Target\r
120 )\r
121{\r
093cceaf
NL
122 MPT_SCSI_DEV *Dev;\r
123\r
124 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
125 if (!IsTargetInitialized (*Target)) {\r
126 ZeroMem (*Target, TARGET_MAX_BYTES);\r
127 } else if (**Target > Dev->MaxTarget) {\r
128 return EFI_INVALID_PARAMETER;\r
129 } else if (**Target < Dev->MaxTarget) {\r
130 //\r
131 // This device interface support 256 targets only, so it's enough to\r
132 // increment the LSB of Target, as it will never overflow.\r
133 //\r
134 **Target += 1;\r
135 } else {\r
136 return EFI_NOT_FOUND;\r
137 }\r
138\r
139 return EFI_SUCCESS;\r
a53e5b41
NL
140}\r
141\r
142STATIC\r
143EFI_STATUS\r
144EFIAPI\r
145MptScsiBuildDevicePath (\r
146 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
147 IN UINT8 *Target,\r
148 IN UINT64 Lun,\r
149 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
150 )\r
151{\r
f9941d31
NL
152 MPT_SCSI_DEV *Dev;\r
153 SCSI_DEVICE_PATH *ScsiDevicePath;\r
154\r
155 if (DevicePath == NULL) {\r
156 return EFI_INVALID_PARAMETER;\r
157 }\r
158\r
159 //\r
160 // This device support 256 targets only, so it's enough to dereference\r
161 // the LSB of Target.\r
162 //\r
163 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
164 if (*Target > Dev->MaxTarget || Lun > 0) {\r
165 return EFI_NOT_FOUND;\r
166 }\r
167\r
168 ScsiDevicePath = AllocateZeroPool (sizeof (*ScsiDevicePath));\r
169 if (ScsiDevicePath == NULL) {\r
170 return EFI_OUT_OF_RESOURCES;\r
171 }\r
172\r
173 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;\r
174 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;\r
175 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);\r
176 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);\r
177 ScsiDevicePath->Pun = *Target;\r
178 ScsiDevicePath->Lun = (UINT16)Lun;\r
179\r
180 *DevicePath = &ScsiDevicePath->Header;\r
181 return EFI_SUCCESS;\r
a53e5b41
NL
182}\r
183\r
184STATIC\r
185EFI_STATUS\r
186EFIAPI\r
187MptScsiGetTargetLun (\r
188 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
189 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
190 OUT UINT8 **Target,\r
191 OUT UINT64 *Lun\r
192 )\r
193{\r
f9941d31
NL
194 MPT_SCSI_DEV *Dev;\r
195 SCSI_DEVICE_PATH *ScsiDevicePath;\r
196\r
197 if (DevicePath == NULL ||\r
198 Target == NULL || *Target == NULL || Lun == NULL) {\r
199 return EFI_INVALID_PARAMETER;\r
200 }\r
201\r
202 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||\r
203 DevicePath->SubType != MSG_SCSI_DP) {\r
204 return EFI_UNSUPPORTED;\r
205 }\r
206\r
207 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
208 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;\r
209 if (ScsiDevicePath->Pun > Dev->MaxTarget ||\r
210 ScsiDevicePath->Lun > 0) {\r
211 return EFI_NOT_FOUND;\r
212 }\r
213\r
214 ZeroMem (*Target, TARGET_MAX_BYTES);\r
215 //\r
216 // This device support 256 targets only, so it's enough to set the LSB\r
217 // of Target.\r
218 //\r
219 **Target = (UINT8)ScsiDevicePath->Pun;\r
220 *Lun = ScsiDevicePath->Lun;\r
221\r
222 return EFI_SUCCESS;\r
a53e5b41
NL
223}\r
224\r
225STATIC\r
226EFI_STATUS\r
227EFIAPI\r
228MptScsiResetChannel (\r
229 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
230 )\r
231{\r
232 return EFI_UNSUPPORTED;\r
233}\r
234\r
235STATIC\r
236EFI_STATUS\r
237EFIAPI\r
238MptScsiResetTargetLun (\r
239 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
240 IN UINT8 *Target,\r
241 IN UINT64 Lun\r
242 )\r
243{\r
244 return EFI_UNSUPPORTED;\r
245}\r
246\r
ad8f2d6b
NL
247//\r
248// Driver Binding\r
249//\r
250\r
251STATIC\r
252EFI_STATUS\r
253EFIAPI\r
254MptScsiControllerSupported (\r
255 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
256 IN EFI_HANDLE ControllerHandle,\r
257 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
258 )\r
259{\r
f4707442
NL
260 EFI_STATUS Status;\r
261 EFI_PCI_IO_PROTOCOL *PciIo;\r
262 PCI_TYPE00 Pci;\r
263\r
264 Status = gBS->OpenProtocol (\r
265 ControllerHandle,\r
266 &gEfiPciIoProtocolGuid,\r
267 (VOID **)&PciIo,\r
268 This->DriverBindingHandle,\r
269 ControllerHandle,\r
270 EFI_OPEN_PROTOCOL_BY_DRIVER\r
271 );\r
272 if (EFI_ERROR (Status)) {\r
273 return Status;\r
274 }\r
275\r
276 Status = PciIo->Pci.Read (\r
277 PciIo,\r
278 EfiPciIoWidthUint32,\r
279 0,\r
280 sizeof (Pci) / sizeof (UINT32),\r
281 &Pci\r
282 );\r
283 if (EFI_ERROR (Status)) {\r
284 goto Done;\r
285 }\r
286\r
287 if (Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID &&\r
288 (Pci.Hdr.DeviceId == LSI_53C1030_PCI_DEVICE_ID ||\r
289 Pci.Hdr.DeviceId == LSI_SAS1068_PCI_DEVICE_ID ||\r
290 Pci.Hdr.DeviceId == LSI_SAS1068E_PCI_DEVICE_ID)) {\r
291 Status = EFI_SUCCESS;\r
292 } else {\r
293 Status = EFI_UNSUPPORTED;\r
294 }\r
295\r
296Done:\r
297 gBS->CloseProtocol (\r
298 ControllerHandle,\r
299 &gEfiPciIoProtocolGuid,\r
300 This->DriverBindingHandle,\r
301 ControllerHandle\r
302 );\r
303 return Status;\r
ad8f2d6b
NL
304}\r
305\r
306STATIC\r
307EFI_STATUS\r
308EFIAPI\r
309MptScsiControllerStart (\r
310 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
311 IN EFI_HANDLE ControllerHandle,\r
312 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
313 )\r
314{\r
a53e5b41
NL
315 EFI_STATUS Status;\r
316 MPT_SCSI_DEV *Dev;\r
317\r
318 Dev = AllocateZeroPool (sizeof (*Dev));\r
319 if (Dev == NULL) {\r
320 return EFI_OUT_OF_RESOURCES;\r
321 }\r
322\r
323 Dev->Signature = MPT_SCSI_DEV_SIGNATURE;\r
324\r
093cceaf
NL
325 Dev->MaxTarget = PcdGet8 (PcdMptScsiMaxTargetLimit);\r
326\r
da8c0b8f
NL
327 Status = gBS->OpenProtocol (\r
328 ControllerHandle,\r
329 &gEfiPciIoProtocolGuid,\r
330 (VOID **)&Dev->PciIo,\r
331 This->DriverBindingHandle,\r
332 ControllerHandle,\r
333 EFI_OPEN_PROTOCOL_BY_DRIVER\r
334 );\r
335 if (EFI_ERROR (Status)) {\r
336 goto FreePool;\r
337 }\r
338\r
ecdbdba6
NL
339 Status = Dev->PciIo->Attributes (\r
340 Dev->PciIo,\r
341 EfiPciIoAttributeOperationGet,\r
342 0,\r
343 &Dev->OriginalPciAttributes\r
344 );\r
345 if (EFI_ERROR (Status)) {\r
346 goto CloseProtocol;\r
347 }\r
348\r
349 //\r
350 // Enable I/O Space & Bus-Mastering\r
351 //\r
352 Status = Dev->PciIo->Attributes (\r
353 Dev->PciIo,\r
354 EfiPciIoAttributeOperationEnable,\r
355 (EFI_PCI_IO_ATTRIBUTE_IO |\r
356 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),\r
357 NULL\r
358 );\r
359 if (EFI_ERROR (Status)) {\r
360 goto CloseProtocol;\r
361 }\r
362\r
363 //\r
364 // Signal device supports 64-bit DMA addresses\r
365 //\r
366 Status = Dev->PciIo->Attributes (\r
367 Dev->PciIo,\r
368 EfiPciIoAttributeOperationEnable,\r
369 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
370 NULL\r
371 );\r
372 if (EFI_ERROR (Status)) {\r
373 //\r
374 // Warn user that device will only be using 32-bit DMA addresses.\r
375 //\r
376 // Note that this does not prevent the device/driver from working\r
377 // and therefore we only warn and continue as usual.\r
378 //\r
379 DEBUG ((\r
380 DEBUG_WARN,\r
381 "%a: failed to enable 64-bit DMA addresses\n",\r
382 __FUNCTION__\r
383 ));\r
384 }\r
385\r
a53e5b41
NL
386 //\r
387 // Host adapter channel, doesn't exist\r
388 //\r
389 Dev->PassThruMode.AdapterId = MAX_UINT32;\r
390 Dev->PassThruMode.Attributes =\r
391 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
392 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
393\r
394 Dev->PassThru.Mode = &Dev->PassThruMode;\r
395 Dev->PassThru.PassThru = &MptScsiPassThru;\r
396 Dev->PassThru.GetNextTargetLun = &MptScsiGetNextTargetLun;\r
397 Dev->PassThru.BuildDevicePath = &MptScsiBuildDevicePath;\r
398 Dev->PassThru.GetTargetLun = &MptScsiGetTargetLun;\r
399 Dev->PassThru.ResetChannel = &MptScsiResetChannel;\r
400 Dev->PassThru.ResetTargetLun = &MptScsiResetTargetLun;\r
401 Dev->PassThru.GetNextTarget = &MptScsiGetNextTarget;\r
402\r
403 Status = gBS->InstallProtocolInterface (\r
404 &ControllerHandle,\r
405 &gEfiExtScsiPassThruProtocolGuid,\r
406 EFI_NATIVE_INTERFACE,\r
407 &Dev->PassThru\r
408 );\r
409 if (EFI_ERROR (Status)) {\r
ecdbdba6 410 goto RestoreAttributes;\r
a53e5b41
NL
411 }\r
412\r
413 return EFI_SUCCESS;\r
414\r
ecdbdba6
NL
415RestoreAttributes:\r
416 Dev->PciIo->Attributes (\r
417 Dev->PciIo,\r
418 EfiPciIoAttributeOperationSet,\r
419 Dev->OriginalPciAttributes,\r
420 NULL\r
421 );\r
422\r
da8c0b8f
NL
423CloseProtocol:\r
424 gBS->CloseProtocol (\r
425 ControllerHandle,\r
426 &gEfiPciIoProtocolGuid,\r
427 This->DriverBindingHandle,\r
428 ControllerHandle\r
429 );\r
430\r
a53e5b41
NL
431FreePool:\r
432 FreePool (Dev);\r
433\r
434 return Status;\r
ad8f2d6b
NL
435}\r
436\r
437STATIC\r
438EFI_STATUS\r
439EFIAPI\r
440MptScsiControllerStop (\r
441 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
442 IN EFI_HANDLE ControllerHandle,\r
443 IN UINTN NumberOfChildren,\r
444 IN EFI_HANDLE *ChildHandleBuffer\r
445 )\r
446{\r
a53e5b41
NL
447 EFI_STATUS Status;\r
448 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
449 MPT_SCSI_DEV *Dev;\r
450\r
451 Status = gBS->OpenProtocol (\r
452 ControllerHandle,\r
453 &gEfiExtScsiPassThruProtocolGuid,\r
454 (VOID **)&PassThru,\r
455 This->DriverBindingHandle,\r
456 ControllerHandle,\r
457 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only\r
458 );\r
459 if (EFI_ERROR (Status)) {\r
460 return Status;\r
461 }\r
462\r
463 Dev = MPT_SCSI_FROM_PASS_THRU (PassThru);\r
464\r
465 Status = gBS->UninstallProtocolInterface (\r
466 ControllerHandle,\r
467 &gEfiExtScsiPassThruProtocolGuid,\r
468 &Dev->PassThru\r
469 );\r
470 if (EFI_ERROR (Status)) {\r
471 return Status;\r
472 }\r
473\r
ecdbdba6
NL
474 Dev->PciIo->Attributes (\r
475 Dev->PciIo,\r
476 EfiPciIoAttributeOperationSet,\r
477 Dev->OriginalPciAttributes,\r
478 NULL\r
479 );\r
480\r
da8c0b8f
NL
481 gBS->CloseProtocol (\r
482 ControllerHandle,\r
483 &gEfiPciIoProtocolGuid,\r
484 This->DriverBindingHandle,\r
485 ControllerHandle\r
486 );\r
487\r
a53e5b41
NL
488 FreePool (Dev);\r
489\r
490 return Status;\r
ad8f2d6b
NL
491}\r
492\r
493STATIC\r
494EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding = {\r
495 &MptScsiControllerSupported,\r
496 &MptScsiControllerStart,\r
497 &MptScsiControllerStop,\r
498 MPT_SCSI_BINDING_VERSION,\r
499 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2\r
500 NULL, // DriverBindingHandle, filled as well\r
501};\r
502\r
be7fcaa1
NL
503//\r
504// Component Name\r
505//\r
506\r
507STATIC\r
508EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
509 { "eng;en", L"LSI Fusion MPT SCSI Driver" },\r
510 { NULL, NULL }\r
511};\r
512\r
513STATIC\r
514EFI_COMPONENT_NAME_PROTOCOL mComponentName;\r
515\r
516EFI_STATUS\r
517EFIAPI\r
518MptScsiGetDriverName (\r
519 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
520 IN CHAR8 *Language,\r
521 OUT CHAR16 **DriverName\r
522 )\r
523{\r
524 return LookupUnicodeString2 (\r
525 Language,\r
526 This->SupportedLanguages,\r
527 mDriverNameTable,\r
528 DriverName,\r
529 (BOOLEAN)(This == &mComponentName) // Iso639Language\r
530 );\r
531}\r
532\r
533EFI_STATUS\r
534EFIAPI\r
535MptScsiGetDeviceName (\r
536 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
537 IN EFI_HANDLE DeviceHandle,\r
538 IN EFI_HANDLE ChildHandle,\r
539 IN CHAR8 *Language,\r
540 OUT CHAR16 **ControllerName\r
541 )\r
542{\r
543 return EFI_UNSUPPORTED;\r
544}\r
545\r
546STATIC\r
547EFI_COMPONENT_NAME_PROTOCOL mComponentName = {\r
548 &MptScsiGetDriverName,\r
549 &MptScsiGetDeviceName,\r
550 "eng" // SupportedLanguages, ISO 639-2 language codes\r
551};\r
552\r
553STATIC\r
554EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {\r
555 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &MptScsiGetDriverName,\r
556 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &MptScsiGetDeviceName,\r
557 "en" // SupportedLanguages, RFC 4646 language codes\r
558};\r
559\r
feec20b2
NL
560//\r
561// Entry Point\r
562//\r
563\r
564EFI_STATUS\r
565EFIAPI\r
566MptScsiEntryPoint (\r
567 IN EFI_HANDLE ImageHandle,\r
568 IN EFI_SYSTEM_TABLE *SystemTable\r
569 )\r
570{\r
ad8f2d6b
NL
571 return EfiLibInstallDriverBindingComponentName2 (\r
572 ImageHandle,\r
573 SystemTable,\r
574 &mMptScsiDriverBinding,\r
575 ImageHandle, // The handle to install onto\r
be7fcaa1
NL
576 &mComponentName,\r
577 &mComponentName2\r
ad8f2d6b 578 );\r
feec20b2 579}\r