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