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