]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/LsiScsiDxe/LsiScsi.c
ShellPkg/Ls: sort output by FileName in non-SFO mode
[mirror_edk2.git] / OvmfPkg / LsiScsiDxe / LsiScsi.c
CommitLineData
e94d04a0
GL
1/** @file\r
2\r
3 This driver produces Extended SCSI Pass Thru Protocol instances for\r
4 LSI 53C895A SCSI devices.\r
5\r
6 Copyright (C) 2020, SUSE LLC.\r
7\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
79f802a5
GL
12#include <IndustryStandard/LsiScsi.h>\r
13#include <IndustryStandard/Pci.h>\r
23d982e2
GL
14#include <Library/BaseLib.h>\r
15#include <Library/BaseMemoryLib.h>\r
16#include <Library/DebugLib.h>\r
17#include <Library/MemoryAllocationLib.h>\r
12d99b8f 18#include <Library/PcdLib.h>\r
79f802a5 19#include <Library/UefiBootServicesTableLib.h>\r
5e6b870a 20#include <Library/UefiLib.h>\r
79f802a5
GL
21#include <Protocol/PciIo.h>\r
22#include <Protocol/PciRootBridgeIo.h>\r
23d982e2 23#include <Protocol/ScsiPassThruExt.h>\r
e94d04a0
GL
24#include <Uefi/UefiSpec.h>\r
25\r
5e6b870a
GL
26#include "LsiScsi.h"\r
27\r
8d619390
GL
28STATIC\r
29EFI_STATUS\r
30Out8 (\r
31 IN LSI_SCSI_DEV *Dev,\r
32 IN UINT32 Addr,\r
33 IN UINT8 Data\r
34 )\r
35{\r
36 return Dev->PciIo->Io.Write (\r
37 Dev->PciIo,\r
38 EfiPciIoWidthUint8,\r
39 PCI_BAR_IDX0,\r
40 Addr,\r
41 1,\r
42 &Data\r
43 );\r
44}\r
45\r
31830b07
GL
46STATIC\r
47EFI_STATUS\r
48Out32 (\r
49 IN LSI_SCSI_DEV *Dev,\r
50 IN UINT32 Addr,\r
51 IN UINT32 Data\r
52 )\r
53{\r
54 return Dev->PciIo->Io.Write (\r
55 Dev->PciIo,\r
56 EfiPciIoWidthUint32,\r
57 PCI_BAR_IDX0,\r
58 Addr,\r
59 1,\r
60 &Data\r
61 );\r
62}\r
63\r
64STATIC\r
65EFI_STATUS\r
66In8 (\r
67 IN LSI_SCSI_DEV *Dev,\r
68 IN UINT32 Addr,\r
69 OUT UINT8 *Data\r
70 )\r
71{\r
72 return Dev->PciIo->Io.Read (\r
73 Dev->PciIo,\r
74 EfiPciIoWidthUint8,\r
75 PCI_BAR_IDX0,\r
76 Addr,\r
77 1,\r
78 Data\r
79 );\r
80}\r
81\r
82STATIC\r
83EFI_STATUS\r
84In32 (\r
85 IN LSI_SCSI_DEV *Dev,\r
86 IN UINT32 Addr,\r
87 OUT UINT32 *Data\r
88 )\r
89{\r
90 return Dev->PciIo->Io.Read (\r
91 Dev->PciIo,\r
92 EfiPciIoWidthUint32,\r
93 PCI_BAR_IDX0,\r
94 Addr,\r
95 1,\r
96 Data\r
97 );\r
98}\r
99\r
8d619390
GL
100STATIC\r
101EFI_STATUS\r
102LsiScsiReset (\r
103 IN LSI_SCSI_DEV *Dev\r
104 )\r
105{\r
106 return Out8 (Dev, LSI_REG_ISTAT0, LSI_ISTAT0_SRST);\r
107}\r
108\r
97e60818
GL
109STATIC\r
110EFI_STATUS\r
111ReportHostAdapterOverrunError (\r
112 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
113 )\r
114{\r
115 Packet->SenseDataLength = 0;\r
116 Packet->HostAdapterStatus =\r
117 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;\r
118 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;\r
119 return EFI_BAD_BUFFER_SIZE;\r
120}\r
121\r
122/**\r
123\r
124 Check the request packet from the Extended SCSI Pass Thru Protocol. The\r
125 request packet is modified, to be forwarded outwards by LsiScsiPassThru(),\r
126 if invalid or unsupported parameters are detected.\r
127\r
128 @param[in] Dev The LSI 53C895A SCSI device the packet targets.\r
129\r
130 @param[in] Target The SCSI target controlled by the LSI 53C895A SCSI\r
131 device.\r
132\r
133 @param[in] Lun The Logical Unit Number under the SCSI target.\r
134\r
135 @param[in out] Packet The Extended SCSI Pass Thru Protocol packet.\r
136\r
137\r
138 @retval EFI_SUCCESS The Extended SCSI Pass Thru Protocol packet was valid.\r
139\r
140 @return Otherwise, invalid or unsupported parameters were\r
141 detected. Status codes are meant for direct forwarding\r
142 by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()\r
143 implementation.\r
144\r
145 **/\r
146STATIC\r
147EFI_STATUS\r
148LsiScsiCheckRequest (\r
149 IN LSI_SCSI_DEV *Dev,\r
150 IN UINT8 Target,\r
151 IN UINT64 Lun,\r
152 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
153 )\r
154{\r
155 if (Target > Dev->MaxTarget || Lun > Dev->MaxLun ||\r
156 Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL ||\r
157 //\r
158 // Trying to receive, but destination pointer is NULL, or contradicting\r
159 // transfer direction\r
160 //\r
161 (Packet->InTransferLength > 0 &&\r
162 (Packet->InDataBuffer == NULL ||\r
163 Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE\r
164 )\r
165 ) ||\r
166\r
167 //\r
168 // Trying to send, but source pointer is NULL, or contradicting transfer\r
169 // direction\r
170 //\r
171 (Packet->OutTransferLength > 0 &&\r
172 (Packet->OutDataBuffer == NULL ||\r
173 Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ\r
174 )\r
175 )\r
176 ) {\r
177 return EFI_INVALID_PARAMETER;\r
178 }\r
179\r
180 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL ||\r
181 (Packet->InTransferLength > 0 && Packet->OutTransferLength > 0) ||\r
182 Packet->CdbLength > sizeof Dev->Dma->Cdb) {\r
183 return EFI_UNSUPPORTED;\r
184 }\r
185\r
186 if (Packet->InTransferLength > sizeof Dev->Dma->Data) {\r
187 Packet->InTransferLength = sizeof Dev->Dma->Data;\r
188 return ReportHostAdapterOverrunError (Packet);\r
189 }\r
190 if (Packet->OutTransferLength > sizeof Dev->Dma->Data) {\r
191 Packet->OutTransferLength = sizeof Dev->Dma->Data;\r
192 return ReportHostAdapterOverrunError (Packet);\r
193 }\r
194\r
195 return EFI_SUCCESS;\r
196}\r
197\r
31830b07
GL
198/**\r
199\r
200 Interpret the request packet from the Extended SCSI Pass Thru Protocol and\r
201 compose the script to submit the command and data to the controller.\r
202\r
203 @param[in] Dev The LSI 53C895A SCSI device the packet targets.\r
204\r
205 @param[in] Target The SCSI target controlled by the LSI 53C895A SCSI\r
206 device.\r
207\r
208 @param[in] Lun The Logical Unit Number under the SCSI target.\r
209\r
210 @param[in out] Packet The Extended SCSI Pass Thru Protocol packet.\r
211\r
212\r
213 @retval EFI_SUCCESS The Extended SCSI Pass Thru Protocol packet was valid.\r
214\r
215 @return Otherwise, invalid or unsupported parameters were\r
216 detected. Status codes are meant for direct forwarding\r
217 by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()\r
218 implementation.\r
219\r
220 **/\r
221STATIC\r
222EFI_STATUS\r
223LsiScsiProcessRequest (\r
224 IN LSI_SCSI_DEV *Dev,\r
225 IN UINT8 Target,\r
226 IN UINT64 Lun,\r
227 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
228 )\r
229{\r
230 EFI_STATUS Status;\r
231 UINT32 *Script;\r
232 UINT8 *Cdb;\r
233 UINT8 *MsgOut;\r
234 UINT8 *MsgIn;\r
235 UINT8 *ScsiStatus;\r
236 UINT8 *Data;\r
237 UINT8 DStat;\r
238 UINT8 SIst0;\r
239 UINT8 SIst1;\r
240 UINT32 Csbc;\r
241 UINT32 CsbcBase;\r
242 UINT32 Transferred;\r
243\r
244 Script = Dev->Dma->Script;\r
245 Cdb = Dev->Dma->Cdb;\r
246 Data = Dev->Dma->Data;\r
247 MsgIn = Dev->Dma->MsgIn;\r
248 MsgOut = &Dev->Dma->MsgOut;\r
249 ScsiStatus = &Dev->Dma->Status;\r
250\r
251 *ScsiStatus = 0xFF;\r
252\r
253 DStat = 0;\r
254 SIst0 = 0;\r
255 SIst1 = 0;\r
256\r
257 SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);\r
258 CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);\r
259\r
260 //\r
261 // Fetch the first Cumulative SCSI Byte Count (CSBC).\r
262 //\r
263 // CSBC is a cumulative counter of the actual number of bytes that have been\r
264 // transferred across the SCSI bus during data phases, i.e. it will not\r
265 // count bytes sent in command, status, message in and out phases.\r
266 //\r
267 Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase);\r
268 if (EFI_ERROR (Status)) {\r
269 goto Error;\r
270 }\r
271\r
272 //\r
273 // Clean up the DMA buffer for the script.\r
274 //\r
275 SetMem (Script, sizeof Dev->Dma->Script, 0x00);\r
276\r
277 //\r
278 // Compose the script to transfer data between the host and the device.\r
279 //\r
280 // References:\r
281 // * LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2\r
282 // - Chapter 5 SCSI SCRIPT Instruction Set\r
283 // * SEABIOS lsi-scsi driver\r
284 //\r
285 // All instructions used here consist of 2 32bit words. The first word\r
286 // contains the command to execute. The second word is loaded into the\r
287 // DMA SCRIPTS Pointer Save (DSPS) register as either the DMA address\r
288 // for data transmission or the address/offset for the jump command.\r
289 // Some commands, such as the selection of the target, don't need to\r
290 // transfer data through DMA or jump to another instruction, then DSPS\r
291 // has to be zero.\r
292 //\r
293 // There are 3 major parts in this script. The first part (1~3) contains\r
294 // the instructions to select target and LUN and send the SCSI command\r
295 // from the request packet. The second part (4~7) is to handle the\r
296 // potential disconnection and prepare for the data transmission. The\r
297 // instructions in the third part (8~10) transmit the given data and\r
298 // collect the result. Instruction 11 raises the interrupt and marks the\r
299 // end of the script.\r
300 //\r
301\r
302 //\r
303 // 1. Select target.\r
304 //\r
305 *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_SEL | (UINT32)Target << 16;\r
306 *Script++ = 0x00000000;\r
307\r
308 //\r
309 // 2. Select LUN.\r
310 //\r
311 *MsgOut = 0x80 | (UINT8) Lun; // 0x80: Identify bit\r
312 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_OUT |\r
313 (UINT32)sizeof Dev->Dma->MsgOut;\r
314 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgOut);\r
315\r
316 //\r
317 // 3. Send the SCSI Command.\r
318 //\r
319 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_CMD |\r
320 (UINT32)sizeof Dev->Dma->Cdb;\r
321 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Cdb);\r
322\r
323 //\r
324 // 4. Check whether the current SCSI phase is "Message In" or not\r
325 // and jump to 7 if it is.\r
326 // Note: LSI_INS_TC_RA stands for "Relative Address Mode", so the\r
327 // offset 0x18 in the second word means jumping forward\r
328 // 3 (0x18/8) instructions.\r
329 //\r
330 *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_JMP |\r
331 LSI_INS_TC_SCSIP_MSG_IN | LSI_INS_TC_RA |\r
332 LSI_INS_TC_CP;\r
333 *Script++ = 0x00000018;\r
334\r
335 //\r
336 // 5. Read "Message" from the initiator to trigger reselect.\r
337 //\r
338 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |\r
339 (UINT32)sizeof Dev->Dma->MsgIn;\r
340 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);\r
341\r
342 //\r
343 // 6. Wait reselect.\r
344 //\r
345 *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_WAIT_RESEL;\r
346 *Script++ = 0x00000000;\r
347\r
348 //\r
349 // 7. Read "Message" from the initiator again\r
350 //\r
351 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |\r
352 (UINT32)sizeof Dev->Dma->MsgIn;\r
353 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);\r
354\r
355 //\r
356 // 8. Set the DMA command for the read/write operations.\r
357 // Note: Some requests, e.g. "TEST UNIT READY", do not come with\r
358 // allocated InDataBuffer or OutDataBuffer. We skip the DMA\r
359 // data command for those requests or this script would fail\r
360 // with LSI_SIST0_SGE due to the zero data length.\r
361 //\r
362 // LsiScsiCheckRequest() prevents both integer overflows in the command\r
363 // opcodes, and buffer overflows.\r
364 //\r
365 if (Packet->InTransferLength > 0) {\r
366 ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ);\r
367 ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);\r
368 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_IN |\r
369 Packet->InTransferLength;\r
370 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);\r
371 } else if (Packet->OutTransferLength > 0) {\r
372 ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE);\r
373 ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);\r
374 CopyMem (Data, Packet->OutDataBuffer, Packet->OutTransferLength);\r
375 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_OUT |\r
376 Packet->OutTransferLength;\r
377 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);\r
378 }\r
379\r
380 //\r
381 // 9. Get the SCSI status.\r
382 //\r
383 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_STAT |\r
384 (UINT32)sizeof Dev->Dma->Status;\r
385 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Status);\r
386\r
387 //\r
388 // 10. Get the SCSI message.\r
389 //\r
390 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |\r
391 (UINT32)sizeof Dev->Dma->MsgIn;\r
392 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);\r
393\r
394 //\r
395 // 11. Raise the interrupt to end the script.\r
396 //\r
397 *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_INT |\r
398 LSI_INS_TC_SCSIP_DAT_OUT | LSI_INS_TC_JMP;\r
399 *Script++ = 0x00000000;\r
400\r
401 //\r
402 // Make sure the size of the script doesn't exceed the buffer.\r
403 //\r
404 ASSERT (Script <= Dev->Dma->Script + ARRAY_SIZE (Dev->Dma->Script));\r
405\r
406 //\r
407 // The controller starts to execute the script once the DMA Script\r
408 // Pointer (DSP) register is set.\r
409 //\r
410 Status = Out32 (Dev, LSI_REG_DSP, LSI_SCSI_DMA_ADDR (Dev, Script));\r
411 if (EFI_ERROR (Status)) {\r
412 goto Error;\r
413 }\r
414\r
415 //\r
416 // Poll the device registers (DSTAT, SIST0, and SIST1) until the SIR\r
417 // bit sets.\r
418 //\r
419 for(;;) {\r
420 Status = In8 (Dev, LSI_REG_DSTAT, &DStat);\r
421 if (EFI_ERROR (Status)) {\r
422 goto Error;\r
423 }\r
424 Status = In8 (Dev, LSI_REG_SIST0, &SIst0);\r
425 if (EFI_ERROR (Status)) {\r
426 goto Error;\r
427 }\r
428 Status = In8 (Dev, LSI_REG_SIST1, &SIst1);\r
429 if (EFI_ERROR (Status)) {\r
430 goto Error;\r
431 }\r
432\r
433 if (SIst0 != 0 || SIst1 != 0) {\r
434 goto Error;\r
435 }\r
436\r
437 //\r
438 // Check the SIR (SCRIPTS Interrupt Instruction Received) bit.\r
439 //\r
440 if (DStat & LSI_DSTAT_SIR) {\r
441 break;\r
442 }\r
443\r
444 gBS->Stall (Dev->StallPerPollUsec);\r
445 }\r
446\r
447 //\r
448 // Check if everything is good.\r
449 // SCSI Message Code 0x00: COMMAND COMPLETE\r
450 // SCSI Status Code 0x00: Good\r
451 //\r
452 if (MsgIn[0] != 0 || *ScsiStatus != 0) {\r
453 goto Error;\r
454 }\r
455\r
456 //\r
457 // Fetch CSBC again to calculate the transferred bytes and update\r
458 // InTransferLength/OutTransferLength.\r
459 //\r
460 // Note: The number of transferred bytes is bounded by\r
461 // "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase\r
462 // from Csbc. If the CSBC register wraps around, the correct\r
463 // difference is ensured by the standard C modular arithmetic.\r
464 //\r
465 Status = In32 (Dev, LSI_REG_CSBC, &Csbc);\r
466 if (EFI_ERROR (Status)) {\r
467 goto Error;\r
468 }\r
469\r
470 Transferred = Csbc - CsbcBase;\r
471 if (Packet->InTransferLength > 0) {\r
472 if (Transferred <= Packet->InTransferLength) {\r
473 Packet->InTransferLength = Transferred;\r
474 } else {\r
475 goto Error;\r
476 }\r
477 } else if (Packet->OutTransferLength > 0) {\r
478 if (Transferred <= Packet->OutTransferLength) {\r
479 Packet->OutTransferLength = Transferred;\r
480 } else {\r
481 goto Error;\r
482 }\r
483 }\r
484\r
485 //\r
486 // Copy Data to InDataBuffer if necessary.\r
487 //\r
488 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
489 CopyMem (Packet->InDataBuffer, Data, Packet->InTransferLength);\r
490 }\r
491\r
492 //\r
493 // Always set SenseDataLength to 0.\r
494 // The instructions of LSI53C895A don't reply sense data. Instead, it\r
495 // relies on the SCSI command, "REQUEST SENSE", to get sense data. We set\r
496 // SenseDataLength to 0 to notify ScsiDiskDxe that there is no sense data\r
497 // written even if this request is processed successfully, so that It will\r
498 // issue "REQUEST SENSE" later to retrieve sense data.\r
499 //\r
500 Packet->SenseDataLength = 0;\r
501 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;\r
502 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;\r
503\r
504 return EFI_SUCCESS;\r
505\r
506Error:\r
507 DEBUG ((DEBUG_VERBOSE, "%a: dstat: %02X, sist0: %02X, sist1: %02X\n",\r
508 __FUNCTION__, DStat, SIst0, SIst1));\r
509 //\r
510 // Update the request packet to reflect the status.\r
511 //\r
512 if (*ScsiStatus != 0xFF) {\r
513 Packet->TargetStatus = *ScsiStatus;\r
514 } else {\r
515 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;\r
516 }\r
517\r
518 if (SIst0 & LSI_SIST0_PAR) {\r
519 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;\r
520 } else if (SIst0 & LSI_SIST0_RST) {\r
521 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;\r
522 } else if (SIst0 & LSI_SIST0_UDC) {\r
523 //\r
524 // The target device is disconnected unexpectedly. According to UEFI spec,\r
525 // this is TIMEOUT_COMMAND.\r
526 //\r
527 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;\r
528 } else if (SIst0 & LSI_SIST0_SGE) {\r
529 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;\r
530 } else if (SIst1 & LSI_SIST1_HTH) {\r
531 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;\r
532 } else if (SIst1 & LSI_SIST1_GEN) {\r
533 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;\r
534 } else if (SIst1 & LSI_SIST1_STO) {\r
535 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;\r
536 } else {\r
537 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;\r
538 }\r
539\r
540 //\r
541 // SenseData may be used to inspect the error. Since we don't set sense data,\r
542 // SenseDataLength has to be 0.\r
543 //\r
544 Packet->SenseDataLength = 0;\r
545\r
546 return EFI_DEVICE_ERROR;\r
547}\r
548\r
23d982e2
GL
549//\r
550// The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL\r
551// for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,\r
552// sections\r
553// - 14.1 SCSI Driver Model Overview,\r
554// - 14.7 Extended SCSI Pass Thru Protocol.\r
555//\r
556\r
557EFI_STATUS\r
558EFIAPI\r
559LsiScsiPassThru (\r
560 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
561 IN UINT8 *Target,\r
562 IN UINT64 Lun,\r
563 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
564 IN EFI_EVENT Event OPTIONAL\r
565 )\r
566{\r
97e60818
GL
567 EFI_STATUS Status;\r
568 LSI_SCSI_DEV *Dev;\r
569\r
570 Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
571 Status = LsiScsiCheckRequest (Dev, *Target, Lun, Packet);\r
572 if (EFI_ERROR (Status)) {\r
573 return Status;\r
574 }\r
575\r
31830b07 576 return LsiScsiProcessRequest (Dev, *Target, Lun, Packet);\r
23d982e2
GL
577}\r
578\r
579EFI_STATUS\r
580EFIAPI\r
581LsiScsiGetNextTargetLun (\r
582 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
583 IN OUT UINT8 **TargetPointer,\r
584 IN OUT UINT64 *Lun\r
585 )\r
586{\r
12d99b8f
GL
587 LSI_SCSI_DEV *Dev;\r
588 UINTN Idx;\r
589 UINT8 *Target;\r
590 UINT16 LastTarget;\r
591\r
592 //\r
593 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer\r
594 //\r
595 Target = *TargetPointer;\r
596\r
597 //\r
598 // Search for first non-0xFF byte. If not found, return first target & LUN.\r
599 //\r
600 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)\r
601 ;\r
602 if (Idx == TARGET_MAX_BYTES) {\r
603 SetMem (Target, TARGET_MAX_BYTES, 0x00);\r
604 *Lun = 0;\r
605 return EFI_SUCCESS;\r
606 }\r
607\r
608 CopyMem (&LastTarget, Target, sizeof LastTarget);\r
609\r
610 //\r
611 // increment (target, LUN) pair if valid on input\r
612 //\r
613 Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
614 if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {\r
615 return EFI_INVALID_PARAMETER;\r
616 }\r
617\r
618 if (*Lun < Dev->MaxLun) {\r
619 ++*Lun;\r
620 return EFI_SUCCESS;\r
621 }\r
622\r
623 if (LastTarget < Dev->MaxTarget) {\r
624 *Lun = 0;\r
625 ++LastTarget;\r
626 CopyMem (Target, &LastTarget, sizeof LastTarget);\r
627 return EFI_SUCCESS;\r
628 }\r
629\r
23d982e2
GL
630 return EFI_NOT_FOUND;\r
631}\r
632\r
633EFI_STATUS\r
634EFIAPI\r
635LsiScsiBuildDevicePath (\r
636 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
637 IN UINT8 *Target,\r
638 IN UINT64 Lun,\r
639 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
640 )\r
641{\r
12d99b8f
GL
642 UINT16 TargetValue;\r
643 LSI_SCSI_DEV *Dev;\r
644 SCSI_DEVICE_PATH *ScsiDevicePath;\r
645\r
646 if (DevicePath == NULL) {\r
647 return EFI_INVALID_PARAMETER;\r
648 }\r
649\r
650 CopyMem (&TargetValue, Target, sizeof TargetValue);\r
651 Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
652 if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun || Lun > 0xFFFF) {\r
653 return EFI_NOT_FOUND;\r
654 }\r
655\r
656 ScsiDevicePath = AllocatePool (sizeof *ScsiDevicePath);\r
657 if (ScsiDevicePath == NULL) {\r
658 return EFI_OUT_OF_RESOURCES;\r
659 }\r
660\r
661 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;\r
662 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;\r
663 ScsiDevicePath->Header.Length[0] = (UINT8) sizeof *ScsiDevicePath;\r
664 ScsiDevicePath->Header.Length[1] = (UINT8) (sizeof *ScsiDevicePath >> 8);\r
665 ScsiDevicePath->Pun = TargetValue;\r
666 ScsiDevicePath->Lun = (UINT16) Lun;\r
667\r
668 *DevicePath = &ScsiDevicePath->Header;\r
669 return EFI_SUCCESS;\r
23d982e2
GL
670}\r
671\r
672EFI_STATUS\r
673EFIAPI\r
674LsiScsiGetTargetLun (\r
675 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
676 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
677 OUT UINT8 **TargetPointer,\r
678 OUT UINT64 *Lun\r
679 )\r
680{\r
12d99b8f
GL
681 SCSI_DEVICE_PATH *ScsiDevicePath;\r
682 LSI_SCSI_DEV *Dev;\r
683 UINT8 *Target;\r
684\r
685 if (DevicePath == NULL || TargetPointer == NULL || *TargetPointer == NULL ||\r
686 Lun == NULL) {\r
687 return EFI_INVALID_PARAMETER;\r
688 }\r
689\r
690 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||\r
691 DevicePath->SubType != MSG_SCSI_DP) {\r
692 return EFI_UNSUPPORTED;\r
693 }\r
694\r
695 ScsiDevicePath = (SCSI_DEVICE_PATH *) DevicePath;\r
696 Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
697 if (ScsiDevicePath->Pun > Dev->MaxTarget ||\r
698 ScsiDevicePath->Lun > Dev->MaxLun) {\r
699 return EFI_NOT_FOUND;\r
700 }\r
701\r
702 Target = *TargetPointer;\r
703 ZeroMem (Target, TARGET_MAX_BYTES);\r
704 CopyMem (Target, &ScsiDevicePath->Pun, sizeof ScsiDevicePath->Pun);\r
705 *Lun = ScsiDevicePath->Lun;\r
706\r
707 return EFI_SUCCESS;\r
23d982e2
GL
708}\r
709\r
710EFI_STATUS\r
711EFIAPI\r
712LsiScsiResetChannel (\r
713 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
714 )\r
715{\r
716 return EFI_UNSUPPORTED;\r
717}\r
718\r
719EFI_STATUS\r
720EFIAPI\r
721LsiScsiResetTargetLun (\r
722 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
723 IN UINT8 *Target,\r
724 IN UINT64 Lun\r
725 )\r
726{\r
727 return EFI_UNSUPPORTED;\r
728}\r
729\r
730EFI_STATUS\r
731EFIAPI\r
732LsiScsiGetNextTarget (\r
733 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
734 IN OUT UINT8 **TargetPointer\r
735 )\r
736{\r
12d99b8f
GL
737 LSI_SCSI_DEV *Dev;\r
738 UINTN Idx;\r
739 UINT8 *Target;\r
740 UINT16 LastTarget;\r
741\r
742 //\r
743 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer\r
744 //\r
745 Target = *TargetPointer;\r
746\r
747 //\r
748 // Search for first non-0xFF byte. If not found, return first target.\r
749 //\r
750 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)\r
751 ;\r
752 if (Idx == TARGET_MAX_BYTES) {\r
753 SetMem (Target, TARGET_MAX_BYTES, 0x00);\r
754 return EFI_SUCCESS;\r
755 }\r
756\r
757 CopyMem (&LastTarget, Target, sizeof LastTarget);\r
758\r
759 //\r
760 // increment target if valid on input\r
761 //\r
762 Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
763 if (LastTarget > Dev->MaxTarget) {\r
764 return EFI_INVALID_PARAMETER;\r
765 }\r
766\r
767 if (LastTarget < Dev->MaxTarget) {\r
768 ++LastTarget;\r
769 CopyMem (Target, &LastTarget, sizeof LastTarget);\r
770 return EFI_SUCCESS;\r
771 }\r
772\r
23d982e2
GL
773 return EFI_NOT_FOUND;\r
774}\r
775\r
8d619390
GL
776STATIC\r
777VOID\r
778EFIAPI\r
779LsiScsiExitBoot (\r
780 IN EFI_EVENT Event,\r
781 IN VOID *Context\r
782 )\r
783{\r
784 LSI_SCSI_DEV *Dev;\r
785\r
786 Dev = Context;\r
787 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));\r
788 LsiScsiReset (Dev);\r
789}\r
790\r
5e6b870a
GL
791//\r
792// Probe, start and stop functions of this driver, called by the DXE core for\r
793// specific devices.\r
794//\r
795// The following specifications document these interfaces:\r
796// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol\r
797// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol\r
798//\r
799\r
800EFI_STATUS\r
801EFIAPI\r
802LsiScsiControllerSupported (\r
803 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
804 IN EFI_HANDLE ControllerHandle,\r
805 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
806 )\r
807{\r
79f802a5
GL
808 EFI_STATUS Status;\r
809 EFI_PCI_IO_PROTOCOL *PciIo;\r
810 PCI_TYPE00 Pci;\r
811\r
812 Status = gBS->OpenProtocol (\r
813 ControllerHandle,\r
814 &gEfiPciIoProtocolGuid,\r
815 (VOID **)&PciIo,\r
816 This->DriverBindingHandle,\r
817 ControllerHandle,\r
818 EFI_OPEN_PROTOCOL_BY_DRIVER\r
819 );\r
820 if (EFI_ERROR (Status)) {\r
821 return Status;\r
822 }\r
823\r
824 Status = PciIo->Pci.Read (\r
825 PciIo,\r
826 EfiPciIoWidthUint32,\r
827 0,\r
828 sizeof (Pci) / sizeof (UINT32),\r
829 &Pci\r
830 );\r
831 if (EFI_ERROR (Status)) {\r
832 goto Done;\r
833 }\r
834\r
835 if (Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID &&\r
836 Pci.Hdr.DeviceId == LSI_53C895A_PCI_DEVICE_ID) {\r
837 Status = EFI_SUCCESS;\r
838 } else {\r
839 Status = EFI_UNSUPPORTED;\r
840 }\r
841\r
842Done:\r
843 gBS->CloseProtocol (\r
844 ControllerHandle,\r
845 &gEfiPciIoProtocolGuid,\r
846 This->DriverBindingHandle,\r
847 ControllerHandle\r
848 );\r
849 return Status;\r
5e6b870a
GL
850}\r
851\r
852EFI_STATUS\r
853EFIAPI\r
854LsiScsiControllerStart (\r
855 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
856 IN EFI_HANDLE ControllerHandle,\r
857 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
858 )\r
859{\r
23d982e2
GL
860 EFI_STATUS Status;\r
861 LSI_SCSI_DEV *Dev;\r
f1d6c1eb
GL
862 UINTN Pages;\r
863 UINTN BytesMapped;\r
23d982e2
GL
864\r
865 Dev = AllocateZeroPool (sizeof (*Dev));\r
866 if (Dev == NULL) {\r
867 return EFI_OUT_OF_RESOURCES;\r
868 }\r
869\r
870 Dev->Signature = LSI_SCSI_DEV_SIGNATURE;\r
871\r
12d99b8f
GL
872 STATIC_ASSERT (\r
873 FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8,\r
874 "LSI 53C895A supports targets [0..7]"\r
875 );\r
876 STATIC_ASSERT (\r
877 FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128,\r
878 "LSI 53C895A supports LUNs [0..127]"\r
879 );\r
880 Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);\r
881 Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);\r
31830b07 882 Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);\r
12d99b8f 883\r
8d619390
GL
884 Status = gBS->OpenProtocol (\r
885 ControllerHandle,\r
886 &gEfiPciIoProtocolGuid,\r
887 (VOID **)&Dev->PciIo,\r
888 This->DriverBindingHandle,\r
889 ControllerHandle,\r
890 EFI_OPEN_PROTOCOL_BY_DRIVER\r
891 );\r
892 if (EFI_ERROR (Status)) {\r
893 goto FreePool;\r
894 }\r
895\r
896 Status = Dev->PciIo->Attributes (\r
897 Dev->PciIo,\r
898 EfiPciIoAttributeOperationGet,\r
899 0,\r
900 &Dev->OrigPciAttrs\r
901 );\r
902 if (EFI_ERROR (Status)) {\r
903 goto CloseProtocol;\r
904 }\r
905\r
906 //\r
907 // Enable I/O Space & Bus-Mastering\r
908 //\r
909 Status = Dev->PciIo->Attributes (\r
910 Dev->PciIo,\r
911 EfiPciIoAttributeOperationEnable,\r
912 (EFI_PCI_IO_ATTRIBUTE_IO |\r
913 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),\r
914 NULL\r
915 );\r
916 if (EFI_ERROR (Status)) {\r
917 goto CloseProtocol;\r
918 }\r
919\r
f1d6c1eb
GL
920 //\r
921 // Create buffers for data transfer\r
922 //\r
923 Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));\r
924 Status = Dev->PciIo->AllocateBuffer (\r
925 Dev->PciIo,\r
926 AllocateAnyPages,\r
927 EfiBootServicesData,\r
928 Pages,\r
929 (VOID **)&Dev->Dma,\r
930 EFI_PCI_ATTRIBUTE_MEMORY_CACHED\r
931 );\r
8d619390
GL
932 if (EFI_ERROR (Status)) {\r
933 goto RestoreAttributes;\r
934 }\r
935\r
f1d6c1eb
GL
936 BytesMapped = EFI_PAGES_TO_SIZE (Pages);\r
937 Status = Dev->PciIo->Map (\r
938 Dev->PciIo,\r
939 EfiPciIoOperationBusMasterCommonBuffer,\r
940 Dev->Dma,\r
941 &BytesMapped,\r
942 &Dev->DmaPhysical,\r
943 &Dev->DmaMapping\r
944 );\r
945 if (EFI_ERROR (Status)) {\r
946 goto FreeBuffer;\r
947 }\r
948\r
949 if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {\r
950 Status = EFI_OUT_OF_RESOURCES;\r
951 goto Unmap;\r
952 }\r
953\r
954 Status = LsiScsiReset (Dev);\r
955 if (EFI_ERROR (Status)) {\r
956 goto Unmap;\r
957 }\r
958\r
8d619390
GL
959 Status = gBS->CreateEvent (\r
960 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
961 TPL_CALLBACK,\r
962 &LsiScsiExitBoot,\r
963 Dev,\r
964 &Dev->ExitBoot\r
965 );\r
966 if (EFI_ERROR (Status)) {\r
967 goto UninitDev;\r
968 }\r
969\r
23d982e2
GL
970 //\r
971 // Host adapter channel, doesn't exist\r
972 //\r
973 Dev->PassThruMode.AdapterId = MAX_UINT32;\r
974 Dev->PassThruMode.Attributes =\r
975 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
976 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
977\r
978 Dev->PassThru.Mode = &Dev->PassThruMode;\r
979 Dev->PassThru.PassThru = &LsiScsiPassThru;\r
980 Dev->PassThru.GetNextTargetLun = &LsiScsiGetNextTargetLun;\r
981 Dev->PassThru.BuildDevicePath = &LsiScsiBuildDevicePath;\r
982 Dev->PassThru.GetTargetLun = &LsiScsiGetTargetLun;\r
983 Dev->PassThru.ResetChannel = &LsiScsiResetChannel;\r
984 Dev->PassThru.ResetTargetLun = &LsiScsiResetTargetLun;\r
985 Dev->PassThru.GetNextTarget = &LsiScsiGetNextTarget;\r
986\r
987 Status = gBS->InstallProtocolInterface (\r
988 &ControllerHandle,\r
989 &gEfiExtScsiPassThruProtocolGuid,\r
990 EFI_NATIVE_INTERFACE,\r
991 &Dev->PassThru\r
992 );\r
993 if (EFI_ERROR (Status)) {\r
8d619390 994 goto CloseExitBoot;\r
23d982e2
GL
995 }\r
996\r
5e6b870a 997 return EFI_SUCCESS;\r
23d982e2 998\r
8d619390
GL
999CloseExitBoot:\r
1000 gBS->CloseEvent (Dev->ExitBoot);\r
1001\r
1002UninitDev:\r
1003 LsiScsiReset (Dev);\r
1004\r
f1d6c1eb
GL
1005Unmap:\r
1006 Dev->PciIo->Unmap (\r
1007 Dev->PciIo,\r
1008 Dev->DmaMapping\r
1009 );\r
1010\r
1011FreeBuffer:\r
1012 Dev->PciIo->FreeBuffer (\r
1013 Dev->PciIo,\r
1014 Pages,\r
1015 Dev->Dma\r
1016 );\r
1017\r
8d619390
GL
1018RestoreAttributes:\r
1019 Dev->PciIo->Attributes (\r
1020 Dev->PciIo,\r
1021 EfiPciIoAttributeOperationSet,\r
1022 Dev->OrigPciAttrs,\r
1023 NULL\r
1024 );\r
1025\r
1026CloseProtocol:\r
1027 gBS->CloseProtocol (\r
1028 ControllerHandle,\r
1029 &gEfiPciIoProtocolGuid,\r
1030 This->DriverBindingHandle,\r
1031 ControllerHandle\r
1032 );\r
1033\r
23d982e2
GL
1034FreePool:\r
1035 FreePool (Dev);\r
1036\r
1037 return Status;\r
5e6b870a
GL
1038}\r
1039\r
1040EFI_STATUS\r
1041EFIAPI\r
1042LsiScsiControllerStop (\r
1043 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1044 IN EFI_HANDLE ControllerHandle,\r
1045 IN UINTN NumberOfChildren,\r
1046 IN EFI_HANDLE *ChildHandleBuffer\r
1047 )\r
1048{\r
23d982e2
GL
1049 EFI_STATUS Status;\r
1050 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
1051 LSI_SCSI_DEV *Dev;\r
1052\r
1053 Status = gBS->OpenProtocol (\r
1054 ControllerHandle,\r
1055 &gEfiExtScsiPassThruProtocolGuid,\r
1056 (VOID **)&PassThru,\r
1057 This->DriverBindingHandle,\r
1058 ControllerHandle,\r
1059 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only\r
1060 );\r
1061 if (EFI_ERROR (Status)) {\r
1062 return Status;\r
1063 }\r
1064\r
1065 Dev = LSI_SCSI_FROM_PASS_THRU (PassThru);\r
1066\r
1067 Status = gBS->UninstallProtocolInterface (\r
1068 ControllerHandle,\r
1069 &gEfiExtScsiPassThruProtocolGuid,\r
1070 &Dev->PassThru\r
1071 );\r
1072 if (EFI_ERROR (Status)) {\r
1073 return Status;\r
1074 }\r
1075\r
8d619390
GL
1076 gBS->CloseEvent (Dev->ExitBoot);\r
1077\r
1078 LsiScsiReset (Dev);\r
1079\r
f1d6c1eb
GL
1080 Dev->PciIo->Unmap (\r
1081 Dev->PciIo,\r
1082 Dev->DmaMapping\r
1083 );\r
1084\r
1085 Dev->PciIo->FreeBuffer (\r
1086 Dev->PciIo,\r
1087 EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),\r
1088 Dev->Dma\r
1089 );\r
1090\r
8d619390
GL
1091 Dev->PciIo->Attributes (\r
1092 Dev->PciIo,\r
1093 EfiPciIoAttributeOperationSet,\r
1094 Dev->OrigPciAttrs,\r
1095 NULL\r
1096 );\r
1097\r
1098 gBS->CloseProtocol (\r
1099 ControllerHandle,\r
1100 &gEfiPciIoProtocolGuid,\r
1101 This->DriverBindingHandle,\r
1102 ControllerHandle\r
1103 );\r
1104\r
23d982e2
GL
1105 FreePool (Dev);\r
1106\r
1107 return Status;\r
5e6b870a
GL
1108}\r
1109\r
1110//\r
1111// The static object that groups the Supported() (ie. probe), Start() and\r
1112// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r
1113// C, 10.1 EFI Driver Binding Protocol.\r
1114//\r
1115STATIC\r
1116EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
1117 &LsiScsiControllerSupported,\r
1118 &LsiScsiControllerStart,\r
1119 &LsiScsiControllerStop,\r
1120 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r
1121 NULL, // ImageHandle, to be overwritten by\r
1122 // EfiLibInstallDriverBindingComponentName2() in LsiScsiEntryPoint()\r
1123 NULL // DriverBindingHandle, ditto\r
1124};\r
1125\r
1126\r
386ca8ab
GL
1127//\r
1128// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r
1129// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r
1130// in English, for display on standard console devices. This is recommended for\r
1131// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's\r
1132// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.\r
1133//\r
1134// Device type names ("LSI 53C895A SCSI Controller") are not formatted because\r
1135// the driver supports only that device type. Therefore the driver name\r
1136// suffices for unambiguous identification.\r
1137//\r
1138\r
1139STATIC\r
1140EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
1141 { "eng;en", L"LSI 53C895A SCSI Controller Driver" },\r
1142 { NULL, NULL }\r
1143};\r
1144\r
1145STATIC\r
1146EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
1147\r
1148EFI_STATUS\r
1149EFIAPI\r
1150LsiScsiGetDriverName (\r
1151 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1152 IN CHAR8 *Language,\r
1153 OUT CHAR16 **DriverName\r
1154 )\r
1155{\r
1156 return LookupUnicodeString2 (\r
1157 Language,\r
1158 This->SupportedLanguages,\r
1159 mDriverNameTable,\r
1160 DriverName,\r
1161 (BOOLEAN)(This == &gComponentName) // Iso639Language\r
1162 );\r
1163}\r
1164\r
1165EFI_STATUS\r
1166EFIAPI\r
1167LsiScsiGetDeviceName (\r
1168 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1169 IN EFI_HANDLE DeviceHandle,\r
1170 IN EFI_HANDLE ChildHandle,\r
1171 IN CHAR8 *Language,\r
1172 OUT CHAR16 **ControllerName\r
1173 )\r
1174{\r
1175 return EFI_UNSUPPORTED;\r
1176}\r
1177\r
1178STATIC\r
1179EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
1180 &LsiScsiGetDriverName,\r
1181 &LsiScsiGetDeviceName,\r
1182 "eng" // SupportedLanguages, ISO 639-2 language codes\r
1183};\r
1184\r
1185STATIC\r
1186EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
1187 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &LsiScsiGetDriverName,\r
1188 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &LsiScsiGetDeviceName,\r
1189 "en" // SupportedLanguages, RFC 4646 language codes\r
1190};\r
1191\r
e94d04a0
GL
1192//\r
1193// Entry point of this driver\r
1194//\r
1195EFI_STATUS\r
1196EFIAPI\r
1197LsiScsiEntryPoint (\r
1198 IN EFI_HANDLE ImageHandle,\r
1199 IN EFI_SYSTEM_TABLE *SystemTable\r
1200 )\r
1201{\r
5e6b870a
GL
1202 return EfiLibInstallDriverBindingComponentName2 (\r
1203 ImageHandle,\r
1204 SystemTable,\r
1205 &gDriverBinding,\r
1206 ImageHandle, // The handle to install onto\r
386ca8ab
GL
1207 &gComponentName,\r
1208 &gComponentName2\r
5e6b870a 1209 );\r
e94d04a0 1210}\r