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