]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/LsiScsiDxe/LsiScsi.c
67fadb411e85debf0d6a695127768db7db0096f0
[mirror_edk2.git] / OvmfPkg / LsiScsiDxe / LsiScsi.c
1 /** @file
2
3 This driver produces Extended SCSI Pass Thru Protocol instances for
4 LSI 53C895A SCSI devices.
5
6 Copyright (C) 2020, SUSE LLC.
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include <IndustryStandard/LsiScsi.h>
13 #include <IndustryStandard/Pci.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/UefiLib.h>
20 #include <Protocol/PciIo.h>
21 #include <Protocol/PciRootBridgeIo.h>
22 #include <Protocol/ScsiPassThruExt.h>
23 #include <Uefi/UefiSpec.h>
24
25 #include "LsiScsi.h"
26
27 //
28 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
29 // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
30 // sections
31 // - 14.1 SCSI Driver Model Overview,
32 // - 14.7 Extended SCSI Pass Thru Protocol.
33 //
34
35 EFI_STATUS
36 EFIAPI
37 LsiScsiPassThru (
38 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
39 IN UINT8 *Target,
40 IN UINT64 Lun,
41 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
42 IN EFI_EVENT Event OPTIONAL
43 )
44 {
45 return EFI_UNSUPPORTED;
46 }
47
48 EFI_STATUS
49 EFIAPI
50 LsiScsiGetNextTargetLun (
51 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
52 IN OUT UINT8 **TargetPointer,
53 IN OUT UINT64 *Lun
54 )
55 {
56 return EFI_NOT_FOUND;
57 }
58
59 EFI_STATUS
60 EFIAPI
61 LsiScsiBuildDevicePath (
62 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
63 IN UINT8 *Target,
64 IN UINT64 Lun,
65 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
66 )
67 {
68 return EFI_NOT_FOUND;
69 }
70
71 EFI_STATUS
72 EFIAPI
73 LsiScsiGetTargetLun (
74 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
75 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
76 OUT UINT8 **TargetPointer,
77 OUT UINT64 *Lun
78 )
79 {
80 return EFI_UNSUPPORTED;
81 }
82
83 EFI_STATUS
84 EFIAPI
85 LsiScsiResetChannel (
86 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
87 )
88 {
89 return EFI_UNSUPPORTED;
90 }
91
92 EFI_STATUS
93 EFIAPI
94 LsiScsiResetTargetLun (
95 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
96 IN UINT8 *Target,
97 IN UINT64 Lun
98 )
99 {
100 return EFI_UNSUPPORTED;
101 }
102
103 EFI_STATUS
104 EFIAPI
105 LsiScsiGetNextTarget (
106 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
107 IN OUT UINT8 **TargetPointer
108 )
109 {
110 return EFI_NOT_FOUND;
111 }
112
113 //
114 // Probe, start and stop functions of this driver, called by the DXE core for
115 // specific devices.
116 //
117 // The following specifications document these interfaces:
118 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
119 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
120 //
121
122 EFI_STATUS
123 EFIAPI
124 LsiScsiControllerSupported (
125 IN EFI_DRIVER_BINDING_PROTOCOL *This,
126 IN EFI_HANDLE ControllerHandle,
127 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
128 )
129 {
130 EFI_STATUS Status;
131 EFI_PCI_IO_PROTOCOL *PciIo;
132 PCI_TYPE00 Pci;
133
134 Status = gBS->OpenProtocol (
135 ControllerHandle,
136 &gEfiPciIoProtocolGuid,
137 (VOID **)&PciIo,
138 This->DriverBindingHandle,
139 ControllerHandle,
140 EFI_OPEN_PROTOCOL_BY_DRIVER
141 );
142 if (EFI_ERROR (Status)) {
143 return Status;
144 }
145
146 Status = PciIo->Pci.Read (
147 PciIo,
148 EfiPciIoWidthUint32,
149 0,
150 sizeof (Pci) / sizeof (UINT32),
151 &Pci
152 );
153 if (EFI_ERROR (Status)) {
154 goto Done;
155 }
156
157 if (Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID &&
158 Pci.Hdr.DeviceId == LSI_53C895A_PCI_DEVICE_ID) {
159 Status = EFI_SUCCESS;
160 } else {
161 Status = EFI_UNSUPPORTED;
162 }
163
164 Done:
165 gBS->CloseProtocol (
166 ControllerHandle,
167 &gEfiPciIoProtocolGuid,
168 This->DriverBindingHandle,
169 ControllerHandle
170 );
171 return Status;
172 }
173
174 EFI_STATUS
175 EFIAPI
176 LsiScsiControllerStart (
177 IN EFI_DRIVER_BINDING_PROTOCOL *This,
178 IN EFI_HANDLE ControllerHandle,
179 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
180 )
181 {
182 EFI_STATUS Status;
183 LSI_SCSI_DEV *Dev;
184
185 Dev = AllocateZeroPool (sizeof (*Dev));
186 if (Dev == NULL) {
187 return EFI_OUT_OF_RESOURCES;
188 }
189
190 Dev->Signature = LSI_SCSI_DEV_SIGNATURE;
191
192 //
193 // Host adapter channel, doesn't exist
194 //
195 Dev->PassThruMode.AdapterId = MAX_UINT32;
196 Dev->PassThruMode.Attributes =
197 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
198 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
199
200 Dev->PassThru.Mode = &Dev->PassThruMode;
201 Dev->PassThru.PassThru = &LsiScsiPassThru;
202 Dev->PassThru.GetNextTargetLun = &LsiScsiGetNextTargetLun;
203 Dev->PassThru.BuildDevicePath = &LsiScsiBuildDevicePath;
204 Dev->PassThru.GetTargetLun = &LsiScsiGetTargetLun;
205 Dev->PassThru.ResetChannel = &LsiScsiResetChannel;
206 Dev->PassThru.ResetTargetLun = &LsiScsiResetTargetLun;
207 Dev->PassThru.GetNextTarget = &LsiScsiGetNextTarget;
208
209 Status = gBS->InstallProtocolInterface (
210 &ControllerHandle,
211 &gEfiExtScsiPassThruProtocolGuid,
212 EFI_NATIVE_INTERFACE,
213 &Dev->PassThru
214 );
215 if (EFI_ERROR (Status)) {
216 goto FreePool;
217 }
218
219 return EFI_SUCCESS;
220
221 FreePool:
222 FreePool (Dev);
223
224 return Status;
225 }
226
227 EFI_STATUS
228 EFIAPI
229 LsiScsiControllerStop (
230 IN EFI_DRIVER_BINDING_PROTOCOL *This,
231 IN EFI_HANDLE ControllerHandle,
232 IN UINTN NumberOfChildren,
233 IN EFI_HANDLE *ChildHandleBuffer
234 )
235 {
236 EFI_STATUS Status;
237 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
238 LSI_SCSI_DEV *Dev;
239
240 Status = gBS->OpenProtocol (
241 ControllerHandle,
242 &gEfiExtScsiPassThruProtocolGuid,
243 (VOID **)&PassThru,
244 This->DriverBindingHandle,
245 ControllerHandle,
246 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
247 );
248 if (EFI_ERROR (Status)) {
249 return Status;
250 }
251
252 Dev = LSI_SCSI_FROM_PASS_THRU (PassThru);
253
254 Status = gBS->UninstallProtocolInterface (
255 ControllerHandle,
256 &gEfiExtScsiPassThruProtocolGuid,
257 &Dev->PassThru
258 );
259 if (EFI_ERROR (Status)) {
260 return Status;
261 }
262
263 FreePool (Dev);
264
265 return Status;
266 }
267
268 //
269 // The static object that groups the Supported() (ie. probe), Start() and
270 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
271 // C, 10.1 EFI Driver Binding Protocol.
272 //
273 STATIC
274 EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
275 &LsiScsiControllerSupported,
276 &LsiScsiControllerStart,
277 &LsiScsiControllerStop,
278 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
279 NULL, // ImageHandle, to be overwritten by
280 // EfiLibInstallDriverBindingComponentName2() in LsiScsiEntryPoint()
281 NULL // DriverBindingHandle, ditto
282 };
283
284
285 //
286 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
287 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
288 // in English, for display on standard console devices. This is recommended for
289 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
290 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
291 //
292 // Device type names ("LSI 53C895A SCSI Controller") are not formatted because
293 // the driver supports only that device type. Therefore the driver name
294 // suffices for unambiguous identification.
295 //
296
297 STATIC
298 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
299 { "eng;en", L"LSI 53C895A SCSI Controller Driver" },
300 { NULL, NULL }
301 };
302
303 STATIC
304 EFI_COMPONENT_NAME_PROTOCOL gComponentName;
305
306 EFI_STATUS
307 EFIAPI
308 LsiScsiGetDriverName (
309 IN EFI_COMPONENT_NAME_PROTOCOL *This,
310 IN CHAR8 *Language,
311 OUT CHAR16 **DriverName
312 )
313 {
314 return LookupUnicodeString2 (
315 Language,
316 This->SupportedLanguages,
317 mDriverNameTable,
318 DriverName,
319 (BOOLEAN)(This == &gComponentName) // Iso639Language
320 );
321 }
322
323 EFI_STATUS
324 EFIAPI
325 LsiScsiGetDeviceName (
326 IN EFI_COMPONENT_NAME_PROTOCOL *This,
327 IN EFI_HANDLE DeviceHandle,
328 IN EFI_HANDLE ChildHandle,
329 IN CHAR8 *Language,
330 OUT CHAR16 **ControllerName
331 )
332 {
333 return EFI_UNSUPPORTED;
334 }
335
336 STATIC
337 EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
338 &LsiScsiGetDriverName,
339 &LsiScsiGetDeviceName,
340 "eng" // SupportedLanguages, ISO 639-2 language codes
341 };
342
343 STATIC
344 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
345 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &LsiScsiGetDriverName,
346 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &LsiScsiGetDeviceName,
347 "en" // SupportedLanguages, RFC 4646 language codes
348 };
349
350 //
351 // Entry point of this driver
352 //
353 EFI_STATUS
354 EFIAPI
355 LsiScsiEntryPoint (
356 IN EFI_HANDLE ImageHandle,
357 IN EFI_SYSTEM_TABLE *SystemTable
358 )
359 {
360 return EfiLibInstallDriverBindingComponentName2 (
361 ImageHandle,
362 SystemTable,
363 &gDriverBinding,
364 ImageHandle, // The handle to install onto
365 &gComponentName,
366 &gComponentName2
367 );
368 }