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