]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/MptScsiDxe/MptScsi.c
OvmfPkg/MptScsiDxe: Open PciIo protocol for later use
[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
a53e5b41
NL
41} MPT_SCSI_DEV;\r
42\r
43#define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \\r
44 CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)\r
45\r
46//\r
47// Ext SCSI Pass Thru\r
48//\r
49\r
50STATIC\r
51EFI_STATUS\r
52EFIAPI\r
53MptScsiPassThru (\r
54 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
55 IN UINT8 *Target,\r
56 IN UINT64 Lun,\r
57 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
58 IN EFI_EVENT Event OPTIONAL\r
59 )\r
60{\r
61 return EFI_UNSUPPORTED;\r
62}\r
63\r
093cceaf
NL
64STATIC\r
65BOOLEAN\r
66IsTargetInitialized (\r
67 IN UINT8 *Target\r
68 )\r
69{\r
70 UINTN Idx;\r
71\r
72 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {\r
73 if (Target[Idx] != 0xFF) {\r
74 return TRUE;\r
75 }\r
76 }\r
77 return FALSE;\r
78}\r
79\r
a53e5b41
NL
80STATIC\r
81EFI_STATUS\r
82EFIAPI\r
83MptScsiGetNextTargetLun (\r
84 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
85 IN OUT UINT8 **Target,\r
86 IN OUT UINT64 *Lun\r
87 )\r
88{\r
093cceaf
NL
89 MPT_SCSI_DEV *Dev;\r
90\r
91 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
92 //\r
93 // Currently support only LUN 0, so hardcode it\r
94 //\r
95 if (!IsTargetInitialized (*Target)) {\r
96 ZeroMem (*Target, TARGET_MAX_BYTES);\r
97 *Lun = 0;\r
98 } else if (**Target > Dev->MaxTarget || *Lun > 0) {\r
99 return EFI_INVALID_PARAMETER;\r
100 } else if (**Target < Dev->MaxTarget) {\r
101 //\r
102 // This device interface support 256 targets only, so it's enough to\r
103 // increment the LSB of Target, as it will never overflow.\r
104 //\r
105 **Target += 1;\r
106 } else {\r
107 return EFI_NOT_FOUND;\r
108 }\r
109\r
110 return EFI_SUCCESS;\r
a53e5b41
NL
111}\r
112\r
113STATIC\r
114EFI_STATUS\r
115EFIAPI\r
116MptScsiGetNextTarget (\r
117 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
118 IN OUT UINT8 **Target\r
119 )\r
120{\r
093cceaf
NL
121 MPT_SCSI_DEV *Dev;\r
122\r
123 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
124 if (!IsTargetInitialized (*Target)) {\r
125 ZeroMem (*Target, TARGET_MAX_BYTES);\r
126 } else if (**Target > Dev->MaxTarget) {\r
127 return EFI_INVALID_PARAMETER;\r
128 } else if (**Target < Dev->MaxTarget) {\r
129 //\r
130 // This device interface support 256 targets only, so it's enough to\r
131 // increment the LSB of Target, as it will never overflow.\r
132 //\r
133 **Target += 1;\r
134 } else {\r
135 return EFI_NOT_FOUND;\r
136 }\r
137\r
138 return EFI_SUCCESS;\r
a53e5b41
NL
139}\r
140\r
141STATIC\r
142EFI_STATUS\r
143EFIAPI\r
144MptScsiBuildDevicePath (\r
145 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
146 IN UINT8 *Target,\r
147 IN UINT64 Lun,\r
148 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
149 )\r
150{\r
f9941d31
NL
151 MPT_SCSI_DEV *Dev;\r
152 SCSI_DEVICE_PATH *ScsiDevicePath;\r
153\r
154 if (DevicePath == NULL) {\r
155 return EFI_INVALID_PARAMETER;\r
156 }\r
157\r
158 //\r
159 // This device support 256 targets only, so it's enough to dereference\r
160 // the LSB of Target.\r
161 //\r
162 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
163 if (*Target > Dev->MaxTarget || Lun > 0) {\r
164 return EFI_NOT_FOUND;\r
165 }\r
166\r
167 ScsiDevicePath = AllocateZeroPool (sizeof (*ScsiDevicePath));\r
168 if (ScsiDevicePath == NULL) {\r
169 return EFI_OUT_OF_RESOURCES;\r
170 }\r
171\r
172 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;\r
173 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;\r
174 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);\r
175 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);\r
176 ScsiDevicePath->Pun = *Target;\r
177 ScsiDevicePath->Lun = (UINT16)Lun;\r
178\r
179 *DevicePath = &ScsiDevicePath->Header;\r
180 return EFI_SUCCESS;\r
a53e5b41
NL
181}\r
182\r
183STATIC\r
184EFI_STATUS\r
185EFIAPI\r
186MptScsiGetTargetLun (\r
187 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
188 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
189 OUT UINT8 **Target,\r
190 OUT UINT64 *Lun\r
191 )\r
192{\r
f9941d31
NL
193 MPT_SCSI_DEV *Dev;\r
194 SCSI_DEVICE_PATH *ScsiDevicePath;\r
195\r
196 if (DevicePath == NULL ||\r
197 Target == NULL || *Target == NULL || Lun == NULL) {\r
198 return EFI_INVALID_PARAMETER;\r
199 }\r
200\r
201 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||\r
202 DevicePath->SubType != MSG_SCSI_DP) {\r
203 return EFI_UNSUPPORTED;\r
204 }\r
205\r
206 Dev = MPT_SCSI_FROM_PASS_THRU (This);\r
207 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;\r
208 if (ScsiDevicePath->Pun > Dev->MaxTarget ||\r
209 ScsiDevicePath->Lun > 0) {\r
210 return EFI_NOT_FOUND;\r
211 }\r
212\r
213 ZeroMem (*Target, TARGET_MAX_BYTES);\r
214 //\r
215 // This device support 256 targets only, so it's enough to set the LSB\r
216 // of Target.\r
217 //\r
218 **Target = (UINT8)ScsiDevicePath->Pun;\r
219 *Lun = ScsiDevicePath->Lun;\r
220\r
221 return EFI_SUCCESS;\r
a53e5b41
NL
222}\r
223\r
224STATIC\r
225EFI_STATUS\r
226EFIAPI\r
227MptScsiResetChannel (\r
228 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
229 )\r
230{\r
231 return EFI_UNSUPPORTED;\r
232}\r
233\r
234STATIC\r
235EFI_STATUS\r
236EFIAPI\r
237MptScsiResetTargetLun (\r
238 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
239 IN UINT8 *Target,\r
240 IN UINT64 Lun\r
241 )\r
242{\r
243 return EFI_UNSUPPORTED;\r
244}\r
245\r
ad8f2d6b
NL
246//\r
247// Driver Binding\r
248//\r
249\r
250STATIC\r
251EFI_STATUS\r
252EFIAPI\r
253MptScsiControllerSupported (\r
254 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
255 IN EFI_HANDLE ControllerHandle,\r
256 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
257 )\r
258{\r
f4707442
NL
259 EFI_STATUS Status;\r
260 EFI_PCI_IO_PROTOCOL *PciIo;\r
261 PCI_TYPE00 Pci;\r
262\r
263 Status = gBS->OpenProtocol (\r
264 ControllerHandle,\r
265 &gEfiPciIoProtocolGuid,\r
266 (VOID **)&PciIo,\r
267 This->DriverBindingHandle,\r
268 ControllerHandle,\r
269 EFI_OPEN_PROTOCOL_BY_DRIVER\r
270 );\r
271 if (EFI_ERROR (Status)) {\r
272 return Status;\r
273 }\r
274\r
275 Status = PciIo->Pci.Read (\r
276 PciIo,\r
277 EfiPciIoWidthUint32,\r
278 0,\r
279 sizeof (Pci) / sizeof (UINT32),\r
280 &Pci\r
281 );\r
282 if (EFI_ERROR (Status)) {\r
283 goto Done;\r
284 }\r
285\r
286 if (Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID &&\r
287 (Pci.Hdr.DeviceId == LSI_53C1030_PCI_DEVICE_ID ||\r
288 Pci.Hdr.DeviceId == LSI_SAS1068_PCI_DEVICE_ID ||\r
289 Pci.Hdr.DeviceId == LSI_SAS1068E_PCI_DEVICE_ID)) {\r
290 Status = EFI_SUCCESS;\r
291 } else {\r
292 Status = EFI_UNSUPPORTED;\r
293 }\r
294\r
295Done:\r
296 gBS->CloseProtocol (\r
297 ControllerHandle,\r
298 &gEfiPciIoProtocolGuid,\r
299 This->DriverBindingHandle,\r
300 ControllerHandle\r
301 );\r
302 return Status;\r
ad8f2d6b
NL
303}\r
304\r
305STATIC\r
306EFI_STATUS\r
307EFIAPI\r
308MptScsiControllerStart (\r
309 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
310 IN EFI_HANDLE ControllerHandle,\r
311 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
312 )\r
313{\r
a53e5b41
NL
314 EFI_STATUS Status;\r
315 MPT_SCSI_DEV *Dev;\r
316\r
317 Dev = AllocateZeroPool (sizeof (*Dev));\r
318 if (Dev == NULL) {\r
319 return EFI_OUT_OF_RESOURCES;\r
320 }\r
321\r
322 Dev->Signature = MPT_SCSI_DEV_SIGNATURE;\r
323\r
093cceaf
NL
324 Dev->MaxTarget = PcdGet8 (PcdMptScsiMaxTargetLimit);\r
325\r
da8c0b8f
NL
326 Status = gBS->OpenProtocol (\r
327 ControllerHandle,\r
328 &gEfiPciIoProtocolGuid,\r
329 (VOID **)&Dev->PciIo,\r
330 This->DriverBindingHandle,\r
331 ControllerHandle,\r
332 EFI_OPEN_PROTOCOL_BY_DRIVER\r
333 );\r
334 if (EFI_ERROR (Status)) {\r
335 goto FreePool;\r
336 }\r
337\r
a53e5b41
NL
338 //\r
339 // Host adapter channel, doesn't exist\r
340 //\r
341 Dev->PassThruMode.AdapterId = MAX_UINT32;\r
342 Dev->PassThruMode.Attributes =\r
343 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
344 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
345\r
346 Dev->PassThru.Mode = &Dev->PassThruMode;\r
347 Dev->PassThru.PassThru = &MptScsiPassThru;\r
348 Dev->PassThru.GetNextTargetLun = &MptScsiGetNextTargetLun;\r
349 Dev->PassThru.BuildDevicePath = &MptScsiBuildDevicePath;\r
350 Dev->PassThru.GetTargetLun = &MptScsiGetTargetLun;\r
351 Dev->PassThru.ResetChannel = &MptScsiResetChannel;\r
352 Dev->PassThru.ResetTargetLun = &MptScsiResetTargetLun;\r
353 Dev->PassThru.GetNextTarget = &MptScsiGetNextTarget;\r
354\r
355 Status = gBS->InstallProtocolInterface (\r
356 &ControllerHandle,\r
357 &gEfiExtScsiPassThruProtocolGuid,\r
358 EFI_NATIVE_INTERFACE,\r
359 &Dev->PassThru\r
360 );\r
361 if (EFI_ERROR (Status)) {\r
da8c0b8f 362 goto CloseProtocol;\r
a53e5b41
NL
363 }\r
364\r
365 return EFI_SUCCESS;\r
366\r
da8c0b8f
NL
367CloseProtocol:\r
368 gBS->CloseProtocol (\r
369 ControllerHandle,\r
370 &gEfiPciIoProtocolGuid,\r
371 This->DriverBindingHandle,\r
372 ControllerHandle\r
373 );\r
374\r
a53e5b41
NL
375FreePool:\r
376 FreePool (Dev);\r
377\r
378 return Status;\r
ad8f2d6b
NL
379}\r
380\r
381STATIC\r
382EFI_STATUS\r
383EFIAPI\r
384MptScsiControllerStop (\r
385 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
386 IN EFI_HANDLE ControllerHandle,\r
387 IN UINTN NumberOfChildren,\r
388 IN EFI_HANDLE *ChildHandleBuffer\r
389 )\r
390{\r
a53e5b41
NL
391 EFI_STATUS Status;\r
392 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
393 MPT_SCSI_DEV *Dev;\r
394\r
395 Status = gBS->OpenProtocol (\r
396 ControllerHandle,\r
397 &gEfiExtScsiPassThruProtocolGuid,\r
398 (VOID **)&PassThru,\r
399 This->DriverBindingHandle,\r
400 ControllerHandle,\r
401 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only\r
402 );\r
403 if (EFI_ERROR (Status)) {\r
404 return Status;\r
405 }\r
406\r
407 Dev = MPT_SCSI_FROM_PASS_THRU (PassThru);\r
408\r
409 Status = gBS->UninstallProtocolInterface (\r
410 ControllerHandle,\r
411 &gEfiExtScsiPassThruProtocolGuid,\r
412 &Dev->PassThru\r
413 );\r
414 if (EFI_ERROR (Status)) {\r
415 return Status;\r
416 }\r
417\r
da8c0b8f
NL
418 gBS->CloseProtocol (\r
419 ControllerHandle,\r
420 &gEfiPciIoProtocolGuid,\r
421 This->DriverBindingHandle,\r
422 ControllerHandle\r
423 );\r
424\r
a53e5b41
NL
425 FreePool (Dev);\r
426\r
427 return Status;\r
ad8f2d6b
NL
428}\r
429\r
430STATIC\r
431EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding = {\r
432 &MptScsiControllerSupported,\r
433 &MptScsiControllerStart,\r
434 &MptScsiControllerStop,\r
435 MPT_SCSI_BINDING_VERSION,\r
436 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2\r
437 NULL, // DriverBindingHandle, filled as well\r
438};\r
439\r
be7fcaa1
NL
440//\r
441// Component Name\r
442//\r
443\r
444STATIC\r
445EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
446 { "eng;en", L"LSI Fusion MPT SCSI Driver" },\r
447 { NULL, NULL }\r
448};\r
449\r
450STATIC\r
451EFI_COMPONENT_NAME_PROTOCOL mComponentName;\r
452\r
453EFI_STATUS\r
454EFIAPI\r
455MptScsiGetDriverName (\r
456 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
457 IN CHAR8 *Language,\r
458 OUT CHAR16 **DriverName\r
459 )\r
460{\r
461 return LookupUnicodeString2 (\r
462 Language,\r
463 This->SupportedLanguages,\r
464 mDriverNameTable,\r
465 DriverName,\r
466 (BOOLEAN)(This == &mComponentName) // Iso639Language\r
467 );\r
468}\r
469\r
470EFI_STATUS\r
471EFIAPI\r
472MptScsiGetDeviceName (\r
473 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
474 IN EFI_HANDLE DeviceHandle,\r
475 IN EFI_HANDLE ChildHandle,\r
476 IN CHAR8 *Language,\r
477 OUT CHAR16 **ControllerName\r
478 )\r
479{\r
480 return EFI_UNSUPPORTED;\r
481}\r
482\r
483STATIC\r
484EFI_COMPONENT_NAME_PROTOCOL mComponentName = {\r
485 &MptScsiGetDriverName,\r
486 &MptScsiGetDeviceName,\r
487 "eng" // SupportedLanguages, ISO 639-2 language codes\r
488};\r
489\r
490STATIC\r
491EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {\r
492 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &MptScsiGetDriverName,\r
493 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &MptScsiGetDeviceName,\r
494 "en" // SupportedLanguages, RFC 4646 language codes\r
495};\r
496\r
feec20b2
NL
497//\r
498// Entry Point\r
499//\r
500\r
501EFI_STATUS\r
502EFIAPI\r
503MptScsiEntryPoint (\r
504 IN EFI_HANDLE ImageHandle,\r
505 IN EFI_SYSTEM_TABLE *SystemTable\r
506 )\r
507{\r
ad8f2d6b
NL
508 return EfiLibInstallDriverBindingComponentName2 (\r
509 ImageHandle,\r
510 SystemTable,\r
511 &mMptScsiDriverBinding,\r
512 ImageHandle, // The handle to install onto\r
be7fcaa1
NL
513 &mComponentName,\r
514 &mComponentName2\r
ad8f2d6b 515 );\r
feec20b2 516}\r