]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/LsiScsiDxe/LsiScsi.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
ac0a286f
MK
31 IN LSI_SCSI_DEV *Dev,\r
32 IN UINT32 Addr,\r
33 IN UINT8 Data\r
8d619390
GL
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
ac0a286f
MK
49 IN LSI_SCSI_DEV *Dev,\r
50 IN UINT32 Addr,\r
51 IN UINT32 Data\r
31830b07
GL
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
ac0a286f
MK
67 IN LSI_SCSI_DEV *Dev,\r
68 IN UINT32 Addr,\r
69 OUT UINT8 *Data\r
31830b07
GL
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
ac0a286f
MK
85 IN LSI_SCSI_DEV *Dev,\r
86 IN UINT32 Addr,\r
87 OUT UINT32 *Data\r
31830b07
GL
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
ac0a286f 103 IN LSI_SCSI_DEV *Dev\r
8d619390
GL
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
ac0a286f 112 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
97e60818
GL
113 )\r
114{\r
ac0a286f 115 Packet->SenseDataLength = 0;\r
97e60818 116 Packet->HostAdapterStatus =\r
ac0a286f 117 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;\r
97e60818
GL
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
ac0a286f
MK
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
97e60818
GL
153 )\r
154{\r
ac0a286f
MK
155 if ((Target > Dev->MaxTarget) || (Lun > Dev->MaxLun) ||\r
156 (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||\r
97e60818
GL
157 //\r
158 // Trying to receive, but destination pointer is NULL, or contradicting\r
159 // transfer direction\r
160 //\r
ac0a286f
MK
161 ((Packet->InTransferLength > 0) &&\r
162 ((Packet->InDataBuffer == NULL) ||\r
163 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)\r
164 )\r
165 ) ||\r
97e60818
GL
166\r
167 //\r
168 // Trying to send, but source pointer is NULL, or contradicting transfer\r
169 // direction\r
170 //\r
ac0a286f
MK
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
97e60818
GL
178 return EFI_INVALID_PARAMETER;\r
179 }\r
180\r
ac0a286f
MK
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
97e60818
GL
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
ac0a286f 192\r
97e60818
GL
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
31830b07
GL
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
ac0a286f
MK
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
31830b07
GL
231 )\r
232{\r
ac0a286f
MK
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
31830b07
GL
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
ac0a286f 314 *MsgOut = 0x80 | (UINT8)Lun; // 0x80: Identify bit\r
31830b07
GL
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
ac0a286f 422 for ( ; ;) {\r
31830b07
GL
423 Status = In8 (Dev, LSI_REG_DSTAT, &DStat);\r
424 if (EFI_ERROR (Status)) {\r
425 goto Error;\r
426 }\r
ac0a286f 427\r
31830b07
GL
428 Status = In8 (Dev, LSI_REG_SIST0, &SIst0);\r
429 if (EFI_ERROR (Status)) {\r
430 goto Error;\r
431 }\r
ac0a286f 432\r
31830b07
GL
433 Status = In8 (Dev, LSI_REG_SIST1, &SIst1);\r
434 if (EFI_ERROR (Status)) {\r
435 goto Error;\r
436 }\r
437\r
ac0a286f 438 if ((SIst0 != 0) || (SIst1 != 0)) {\r
31830b07
GL
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
ac0a286f 457 if ((MsgIn[0] != 0) || (*ScsiStatus != 0)) {\r
31830b07
GL
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
ac0a286f
MK
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
31830b07
GL
520 //\r
521 // Update the request packet to reflect the status.\r
522 //\r
523 if (*ScsiStatus != 0xFF) {\r
ac0a286f 524 Packet->TargetStatus = *ScsiStatus;\r
31830b07 525 } else {\r
ac0a286f 526 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;\r
31830b07
GL
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
23d982e2
GL
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
ac0a286f
MK
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
23d982e2
GL
576 )\r
577{\r
ac0a286f
MK
578 EFI_STATUS Status;\r
579 LSI_SCSI_DEV *Dev;\r
97e60818 580\r
ac0a286f 581 Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
97e60818
GL
582 Status = LsiScsiCheckRequest (Dev, *Target, Lun, Packet);\r
583 if (EFI_ERROR (Status)) {\r
584 return Status;\r
585 }\r
586\r
31830b07 587 return LsiScsiProcessRequest (Dev, *Target, Lun, Packet);\r
23d982e2
GL
588}\r
589\r
590EFI_STATUS\r
591EFIAPI\r
592LsiScsiGetNextTargetLun (\r
ac0a286f
MK
593 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
594 IN OUT UINT8 **TargetPointer,\r
595 IN OUT UINT64 *Lun\r
23d982e2
GL
596 )\r
597{\r
ac0a286f
MK
598 LSI_SCSI_DEV *Dev;\r
599 UINTN Idx;\r
600 UINT8 *Target;\r
601 UINT16 LastTarget;\r
12d99b8f
GL
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
ac0a286f
MK
611 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx) {\r
612 }\r
613\r
12d99b8f
GL
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
ac0a286f 626 if ((LastTarget > Dev->MaxTarget) || (*Lun > Dev->MaxLun)) {\r
12d99b8f
GL
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
23d982e2
GL
642 return EFI_NOT_FOUND;\r
643}\r
644\r
645EFI_STATUS\r
646EFIAPI\r
647LsiScsiBuildDevicePath (\r
ac0a286f
MK
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
23d982e2
GL
652 )\r
653{\r
ac0a286f
MK
654 UINT16 TargetValue;\r
655 LSI_SCSI_DEV *Dev;\r
656 SCSI_DEVICE_PATH *ScsiDevicePath;\r
12d99b8f
GL
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
ac0a286f 664 if ((TargetValue > Dev->MaxTarget) || (Lun > Dev->MaxLun) || (Lun > 0xFFFF)) {\r
12d99b8f
GL
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
ac0a286f
MK
675 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof *ScsiDevicePath;\r
676 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof *ScsiDevicePath >> 8);\r
12d99b8f 677 ScsiDevicePath->Pun = TargetValue;\r
ac0a286f 678 ScsiDevicePath->Lun = (UINT16)Lun;\r
12d99b8f
GL
679\r
680 *DevicePath = &ScsiDevicePath->Header;\r
681 return EFI_SUCCESS;\r
23d982e2
GL
682}\r
683\r
684EFI_STATUS\r
685EFIAPI\r
686LsiScsiGetTargetLun (\r
ac0a286f
MK
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
23d982e2
GL
691 )\r
692{\r
ac0a286f
MK
693 SCSI_DEVICE_PATH *ScsiDevicePath;\r
694 LSI_SCSI_DEV *Dev;\r
695 UINT8 *Target;\r
12d99b8f 696\r
ac0a286f
MK
697 if ((DevicePath == NULL) || (TargetPointer == NULL) || (*TargetPointer == NULL) ||\r
698 (Lun == NULL))\r
699 {\r
12d99b8f
GL
700 return EFI_INVALID_PARAMETER;\r
701 }\r
702\r
ac0a286f
MK
703 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
704 (DevicePath->SubType != MSG_SCSI_DP))\r
705 {\r
12d99b8f
GL
706 return EFI_UNSUPPORTED;\r
707 }\r
708\r
ac0a286f
MK
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
12d99b8f
GL
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
23d982e2
GL
723}\r
724\r
725EFI_STATUS\r
726EFIAPI\r
727LsiScsiResetChannel (\r
ac0a286f 728 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
23d982e2
GL
729 )\r
730{\r
731 return EFI_UNSUPPORTED;\r
732}\r
733\r
734EFI_STATUS\r
735EFIAPI\r
736LsiScsiResetTargetLun (\r
ac0a286f
MK
737 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
738 IN UINT8 *Target,\r
739 IN UINT64 Lun\r
23d982e2
GL
740 )\r
741{\r
742 return EFI_UNSUPPORTED;\r
743}\r
744\r
745EFI_STATUS\r
746EFIAPI\r
747LsiScsiGetNextTarget (\r
ac0a286f
MK
748 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
749 IN OUT UINT8 **TargetPointer\r
23d982e2
GL
750 )\r
751{\r
ac0a286f
MK
752 LSI_SCSI_DEV *Dev;\r
753 UINTN Idx;\r
754 UINT8 *Target;\r
755 UINT16 LastTarget;\r
12d99b8f
GL
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
ac0a286f
MK
765 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx) {\r
766 }\r
767\r
12d99b8f
GL
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
23d982e2
GL
789 return EFI_NOT_FOUND;\r
790}\r
791\r
8d619390
GL
792STATIC\r
793VOID\r
794EFIAPI\r
795LsiScsiExitBoot (\r
ac0a286f
MK
796 IN EFI_EVENT Event,\r
797 IN VOID *Context\r
8d619390
GL
798 )\r
799{\r
ac0a286f 800 LSI_SCSI_DEV *Dev;\r
8d619390
GL
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
5e6b870a
GL
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
ac0a286f
MK
819 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
820 IN EFI_HANDLE ControllerHandle,\r
821 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
5e6b870a
GL
822 )\r
823{\r
ac0a286f
MK
824 EFI_STATUS Status;\r
825 EFI_PCI_IO_PROTOCOL *PciIo;\r
826 PCI_TYPE00 Pci;\r
79f802a5
GL
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
ac0a286f
MK
851 if ((Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID) &&\r
852 (Pci.Hdr.DeviceId == LSI_53C895A_PCI_DEVICE_ID))\r
853 {\r
79f802a5
GL
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
5e6b870a
GL
867}\r
868\r
869EFI_STATUS\r
870EFIAPI\r
871LsiScsiControllerStart (\r
ac0a286f
MK
872 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
873 IN EFI_HANDLE ControllerHandle,\r
874 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
5e6b870a
GL
875 )\r
876{\r
ac0a286f
MK
877 EFI_STATUS Status;\r
878 LSI_SCSI_DEV *Dev;\r
879 UINTN Pages;\r
880 UINTN BytesMapped;\r
23d982e2
GL
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
12d99b8f
GL
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
ac0a286f
MK
897 Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);\r
898 Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);\r
31830b07 899 Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);\r
12d99b8f 900\r
8d619390
GL
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
f1d6c1eb
GL
937 //\r
938 // Create buffers for data transfer\r
939 //\r
ac0a286f 940 Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));\r
f1d6c1eb
GL
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
8d619390
GL
949 if (EFI_ERROR (Status)) {\r
950 goto RestoreAttributes;\r
951 }\r
952\r
f1d6c1eb 953 BytesMapped = EFI_PAGES_TO_SIZE (Pages);\r
ac0a286f
MK
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
f1d6c1eb
GL
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
8d619390
GL
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
23d982e2
GL
987 //\r
988 // Host adapter channel, doesn't exist\r
989 //\r
ac0a286f 990 Dev->PassThruMode.AdapterId = MAX_UINT32;\r
23d982e2
GL
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
ac0a286f
MK
995 Dev->PassThru.Mode = &Dev->PassThruMode;\r
996 Dev->PassThru.PassThru = &LsiScsiPassThru;\r
23d982e2 997 Dev->PassThru.GetNextTargetLun = &LsiScsiGetNextTargetLun;\r
ac0a286f
MK
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
23d982e2
GL
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
8d619390 1011 goto CloseExitBoot;\r
23d982e2
GL
1012 }\r
1013\r
5e6b870a 1014 return EFI_SUCCESS;\r
23d982e2 1015\r
8d619390
GL
1016CloseExitBoot:\r
1017 gBS->CloseEvent (Dev->ExitBoot);\r
1018\r
1019UninitDev:\r
1020 LsiScsiReset (Dev);\r
1021\r
f1d6c1eb
GL
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
8d619390
GL
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
23d982e2
GL
1051FreePool:\r
1052 FreePool (Dev);\r
1053\r
1054 return Status;\r
5e6b870a
GL
1055}\r
1056\r
1057EFI_STATUS\r
1058EFIAPI\r
1059LsiScsiControllerStop (\r
ac0a286f
MK
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
5e6b870a
GL
1064 )\r
1065{\r
ac0a286f
MK
1066 EFI_STATUS Status;\r
1067 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
1068 LSI_SCSI_DEV *Dev;\r
23d982e2
GL
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
8d619390
GL
1093 gBS->CloseEvent (Dev->ExitBoot);\r
1094\r
1095 LsiScsiReset (Dev);\r
1096\r
f1d6c1eb
GL
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
8d619390
GL
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
23d982e2
GL
1122 FreePool (Dev);\r
1123\r
1124 return Status;\r
5e6b870a
GL
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
ac0a286f 1133EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
5e6b870a
GL
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
386ca8ab
GL
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
ac0a286f 1156EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
386ca8ab
GL
1157 { "eng;en", L"LSI 53C895A SCSI Controller Driver" },\r
1158 { NULL, NULL }\r
1159};\r
1160\r
1161STATIC\r
ac0a286f 1162EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
386ca8ab
GL
1163\r
1164EFI_STATUS\r
1165EFIAPI\r
1166LsiScsiGetDriverName (\r
ac0a286f
MK
1167 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1168 IN CHAR8 *Language,\r
1169 OUT CHAR16 **DriverName\r
386ca8ab
GL
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
ac0a286f
MK
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
386ca8ab
GL
1189 )\r
1190{\r
1191 return EFI_UNSUPPORTED;\r
1192}\r
1193\r
1194STATIC\r
ac0a286f 1195EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
386ca8ab
GL
1196 &LsiScsiGetDriverName,\r
1197 &LsiScsiGetDeviceName,\r
1198 "eng" // SupportedLanguages, ISO 639-2 language codes\r
1199};\r
1200\r
1201STATIC\r
ac0a286f
MK
1202EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
1203 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&LsiScsiGetDriverName,\r
1204 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&LsiScsiGetDeviceName,\r
386ca8ab
GL
1205 "en" // SupportedLanguages, RFC 4646 language codes\r
1206};\r
1207\r
e94d04a0
GL
1208//\r
1209// Entry point of this driver\r
1210//\r
1211EFI_STATUS\r
1212EFIAPI\r
1213LsiScsiEntryPoint (\r
ac0a286f
MK
1214 IN EFI_HANDLE ImageHandle,\r
1215 IN EFI_SYSTEM_TABLE *SystemTable\r
e94d04a0
GL
1216 )\r
1217{\r
5e6b870a
GL
1218 return EfiLibInstallDriverBindingComponentName2 (\r
1219 ImageHandle,\r
1220 SystemTable,\r
1221 &gDriverBinding,\r
1222 ImageHandle, // The handle to install onto\r
386ca8ab
GL
1223 &gComponentName,\r
1224 &gComponentName2\r
5e6b870a 1225 );\r
e94d04a0 1226}\r