3 This driver produces Extended SCSI Pass Thru Protocol instances for
4 LSI 53C895A SCSI devices.
6 Copyright (C) 2020, SUSE LLC.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <IndustryStandard/LsiScsi.h>
13 #include <IndustryStandard/Pci.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiLib.h>
21 #include <Protocol/PciIo.h>
22 #include <Protocol/PciRootBridgeIo.h>
23 #include <Protocol/ScsiPassThruExt.h>
24 #include <Uefi/UefiSpec.h>
36 return Dev
->PciIo
->Io
.Write (
54 return Dev
->PciIo
->Io
.Write (
72 return Dev
->PciIo
->Io
.Read (
90 return Dev
->PciIo
->Io
.Read (
106 return Out8 (Dev
, LSI_REG_ISTAT0
, LSI_ISTAT0_SRST
);
111 ReportHostAdapterOverrunError (
112 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
115 Packet
->SenseDataLength
= 0;
116 Packet
->HostAdapterStatus
=
117 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
118 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
119 return EFI_BAD_BUFFER_SIZE
;
124 Check the request packet from the Extended SCSI Pass Thru Protocol. The
125 request packet is modified, to be forwarded outwards by LsiScsiPassThru(),
126 if invalid or unsupported parameters are detected.
128 @param[in] Dev The LSI 53C895A SCSI device the packet targets.
130 @param[in] Target The SCSI target controlled by the LSI 53C895A SCSI
133 @param[in] Lun The Logical Unit Number under the SCSI target.
135 @param[in out] Packet The Extended SCSI Pass Thru Protocol packet.
138 @retval EFI_SUCCESS The Extended SCSI Pass Thru Protocol packet was valid.
140 @return Otherwise, invalid or unsupported parameters were
141 detected. Status codes are meant for direct forwarding
142 by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
148 LsiScsiCheckRequest (
149 IN LSI_SCSI_DEV
*Dev
,
152 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
155 if ((Target
> Dev
->MaxTarget
) || (Lun
> Dev
->MaxLun
) ||
156 (Packet
->DataDirection
> EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
) ||
158 // Trying to receive, but destination pointer is NULL, or contradicting
159 // transfer direction
161 ((Packet
->InTransferLength
> 0) &&
162 ((Packet
->InDataBuffer
== NULL
) ||
163 (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_WRITE
)
168 // Trying to send, but source pointer is NULL, or contradicting transfer
171 ((Packet
->OutTransferLength
> 0) &&
172 ((Packet
->OutDataBuffer
== NULL
) ||
173 (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
)
178 return EFI_INVALID_PARAMETER
;
181 if ((Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
) ||
182 ((Packet
->InTransferLength
> 0) && (Packet
->OutTransferLength
> 0)) ||
183 (Packet
->CdbLength
> sizeof Dev
->Dma
->Cdb
))
185 return EFI_UNSUPPORTED
;
188 if (Packet
->InTransferLength
> sizeof Dev
->Dma
->Data
) {
189 Packet
->InTransferLength
= sizeof Dev
->Dma
->Data
;
190 return ReportHostAdapterOverrunError (Packet
);
193 if (Packet
->OutTransferLength
> sizeof Dev
->Dma
->Data
) {
194 Packet
->OutTransferLength
= sizeof Dev
->Dma
->Data
;
195 return ReportHostAdapterOverrunError (Packet
);
203 Interpret the request packet from the Extended SCSI Pass Thru Protocol and
204 compose the script to submit the command and data to the controller.
206 @param[in] Dev The LSI 53C895A SCSI device the packet targets.
208 @param[in] Target The SCSI target controlled by the LSI 53C895A SCSI
211 @param[in] Lun The Logical Unit Number under the SCSI target.
213 @param[in out] Packet The Extended SCSI Pass Thru Protocol packet.
216 @retval EFI_SUCCESS The Extended SCSI Pass Thru Protocol packet was valid.
218 @return Otherwise, invalid or unsupported parameters were
219 detected. Status codes are meant for direct forwarding
220 by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
226 LsiScsiProcessRequest (
227 IN LSI_SCSI_DEV
*Dev
,
230 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
247 Script
= Dev
->Dma
->Script
;
249 Data
= Dev
->Dma
->Data
;
250 MsgIn
= Dev
->Dma
->MsgIn
;
251 MsgOut
= &Dev
->Dma
->MsgOut
;
252 ScsiStatus
= &Dev
->Dma
->Status
;
260 SetMem (Cdb
, sizeof Dev
->Dma
->Cdb
, 0x00);
261 CopyMem (Cdb
, Packet
->Cdb
, Packet
->CdbLength
);
264 // Fetch the first Cumulative SCSI Byte Count (CSBC).
266 // CSBC is a cumulative counter of the actual number of bytes that have been
267 // transferred across the SCSI bus during data phases, i.e. it will not
268 // count bytes sent in command, status, message in and out phases.
270 Status
= In32 (Dev
, LSI_REG_CSBC
, &CsbcBase
);
271 if (EFI_ERROR (Status
)) {
276 // Clean up the DMA buffer for the script.
278 SetMem (Script
, sizeof Dev
->Dma
->Script
, 0x00);
281 // Compose the script to transfer data between the host and the device.
284 // * LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2
285 // - Chapter 5 SCSI SCRIPT Instruction Set
286 // * SEABIOS lsi-scsi driver
288 // All instructions used here consist of 2 32bit words. The first word
289 // contains the command to execute. The second word is loaded into the
290 // DMA SCRIPTS Pointer Save (DSPS) register as either the DMA address
291 // for data transmission or the address/offset for the jump command.
292 // Some commands, such as the selection of the target, don't need to
293 // transfer data through DMA or jump to another instruction, then DSPS
296 // There are 3 major parts in this script. The first part (1~3) contains
297 // the instructions to select target and LUN and send the SCSI command
298 // from the request packet. The second part (4~7) is to handle the
299 // potential disconnection and prepare for the data transmission. The
300 // instructions in the third part (8~10) transmit the given data and
301 // collect the result. Instruction 11 raises the interrupt and marks the
302 // end of the script.
308 *Script
++ = LSI_INS_TYPE_IO
| LSI_INS_IO_OPC_SEL
| (UINT32
)Target
<< 16;
309 *Script
++ = 0x00000000;
314 *MsgOut
= 0x80 | (UINT8
)Lun
; // 0x80: Identify bit
315 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_MSG_OUT
|
316 (UINT32
)sizeof Dev
->Dma
->MsgOut
;
317 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, MsgOut
);
320 // 3. Send the SCSI Command.
322 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_CMD
|
323 (UINT32
)sizeof Dev
->Dma
->Cdb
;
324 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, Cdb
);
327 // 4. Check whether the current SCSI phase is "Message In" or not
328 // and jump to 7 if it is.
329 // Note: LSI_INS_TC_RA stands for "Relative Address Mode", so the
330 // offset 0x18 in the second word means jumping forward
331 // 3 (0x18/8) instructions.
333 *Script
++ = LSI_INS_TYPE_TC
| LSI_INS_TC_OPC_JMP
|
334 LSI_INS_TC_SCSIP_MSG_IN
| LSI_INS_TC_RA
|
336 *Script
++ = 0x00000018;
339 // 5. Read "Message" from the initiator to trigger reselect.
341 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_MSG_IN
|
342 (UINT32
)sizeof Dev
->Dma
->MsgIn
;
343 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, MsgIn
);
348 *Script
++ = LSI_INS_TYPE_IO
| LSI_INS_IO_OPC_WAIT_RESEL
;
349 *Script
++ = 0x00000000;
352 // 7. Read "Message" from the initiator again
354 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_MSG_IN
|
355 (UINT32
)sizeof Dev
->Dma
->MsgIn
;
356 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, MsgIn
);
359 // 8. Set the DMA command for the read/write operations.
360 // Note: Some requests, e.g. "TEST UNIT READY", do not come with
361 // allocated InDataBuffer or OutDataBuffer. We skip the DMA
362 // data command for those requests or this script would fail
363 // with LSI_SIST0_SGE due to the zero data length.
365 // LsiScsiCheckRequest() prevents both integer overflows in the command
366 // opcodes, and buffer overflows.
368 if (Packet
->InTransferLength
> 0) {
369 ASSERT (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
);
370 ASSERT (Packet
->InTransferLength
<= sizeof Dev
->Dma
->Data
);
371 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_DAT_IN
|
372 Packet
->InTransferLength
;
373 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, Data
);
374 } else if (Packet
->OutTransferLength
> 0) {
375 ASSERT (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_WRITE
);
376 ASSERT (Packet
->OutTransferLength
<= sizeof Dev
->Dma
->Data
);
377 CopyMem (Data
, Packet
->OutDataBuffer
, Packet
->OutTransferLength
);
378 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_DAT_OUT
|
379 Packet
->OutTransferLength
;
380 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, Data
);
384 // 9. Get the SCSI status.
386 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_STAT
|
387 (UINT32
)sizeof Dev
->Dma
->Status
;
388 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, Status
);
391 // 10. Get the SCSI message.
393 *Script
++ = LSI_INS_TYPE_BLK
| LSI_INS_BLK_SCSIP_MSG_IN
|
394 (UINT32
)sizeof Dev
->Dma
->MsgIn
;
395 *Script
++ = LSI_SCSI_DMA_ADDR (Dev
, MsgIn
);
398 // 11. Raise the interrupt to end the script.
400 *Script
++ = LSI_INS_TYPE_TC
| LSI_INS_TC_OPC_INT
|
401 LSI_INS_TC_SCSIP_DAT_OUT
| LSI_INS_TC_JMP
;
402 *Script
++ = 0x00000000;
405 // Make sure the size of the script doesn't exceed the buffer.
407 ASSERT (Script
<= Dev
->Dma
->Script
+ ARRAY_SIZE (Dev
->Dma
->Script
));
410 // The controller starts to execute the script once the DMA Script
411 // Pointer (DSP) register is set.
413 Status
= Out32 (Dev
, LSI_REG_DSP
, LSI_SCSI_DMA_ADDR (Dev
, Script
));
414 if (EFI_ERROR (Status
)) {
419 // Poll the device registers (DSTAT, SIST0, and SIST1) until the SIR
423 Status
= In8 (Dev
, LSI_REG_DSTAT
, &DStat
);
424 if (EFI_ERROR (Status
)) {
428 Status
= In8 (Dev
, LSI_REG_SIST0
, &SIst0
);
429 if (EFI_ERROR (Status
)) {
433 Status
= In8 (Dev
, LSI_REG_SIST1
, &SIst1
);
434 if (EFI_ERROR (Status
)) {
438 if ((SIst0
!= 0) || (SIst1
!= 0)) {
443 // Check the SIR (SCRIPTS Interrupt Instruction Received) bit.
445 if (DStat
& LSI_DSTAT_SIR
) {
449 gBS
->Stall (Dev
->StallPerPollUsec
);
453 // Check if everything is good.
454 // SCSI Message Code 0x00: COMMAND COMPLETE
455 // SCSI Status Code 0x00: Good
457 if ((MsgIn
[0] != 0) || (*ScsiStatus
!= 0)) {
462 // Fetch CSBC again to calculate the transferred bytes and update
463 // InTransferLength/OutTransferLength.
465 // Note: The number of transferred bytes is bounded by
466 // "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase
467 // from Csbc. If the CSBC register wraps around, the correct
468 // difference is ensured by the standard C modular arithmetic.
470 Status
= In32 (Dev
, LSI_REG_CSBC
, &Csbc
);
471 if (EFI_ERROR (Status
)) {
475 Transferred
= Csbc
- CsbcBase
;
476 if (Packet
->InTransferLength
> 0) {
477 if (Transferred
<= Packet
->InTransferLength
) {
478 Packet
->InTransferLength
= Transferred
;
482 } else if (Packet
->OutTransferLength
> 0) {
483 if (Transferred
<= Packet
->OutTransferLength
) {
484 Packet
->OutTransferLength
= Transferred
;
491 // Copy Data to InDataBuffer if necessary.
493 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
494 CopyMem (Packet
->InDataBuffer
, Data
, Packet
->InTransferLength
);
498 // Always set SenseDataLength to 0.
499 // The instructions of LSI53C895A don't reply sense data. Instead, it
500 // relies on the SCSI command, "REQUEST SENSE", to get sense data. We set
501 // SenseDataLength to 0 to notify ScsiDiskDxe that there is no sense data
502 // written even if this request is processed successfully, so that It will
503 // issue "REQUEST SENSE" later to retrieve sense data.
505 Packet
->SenseDataLength
= 0;
506 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
;
507 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_GOOD
;
514 "%a: dstat: %02X, sist0: %02X, sist1: %02X\n",
521 // Update the request packet to reflect the status.
523 if (*ScsiStatus
!= 0xFF) {
524 Packet
->TargetStatus
= *ScsiStatus
;
526 Packet
->TargetStatus
= EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED
;
529 if (SIst0
& LSI_SIST0_PAR
) {
530 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
;
531 } else if (SIst0
& LSI_SIST0_RST
) {
532 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
;
533 } else if (SIst0
& LSI_SIST0_UDC
) {
535 // The target device is disconnected unexpectedly. According to UEFI spec,
536 // this is TIMEOUT_COMMAND.
538 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
539 } else if (SIst0
& LSI_SIST0_SGE
) {
540 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
;
541 } else if (SIst1
& LSI_SIST1_HTH
) {
542 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
;
543 } else if (SIst1
& LSI_SIST1_GEN
) {
544 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
;
545 } else if (SIst1
& LSI_SIST1_STO
) {
546 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
;
548 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER
;
552 // SenseData may be used to inspect the error. Since we don't set sense data,
553 // SenseDataLength has to be 0.
555 Packet
->SenseDataLength
= 0;
557 return EFI_DEVICE_ERROR
;
561 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
562 // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
564 // - 14.1 SCSI Driver Model Overview,
565 // - 14.7 Extended SCSI Pass Thru Protocol.
571 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
574 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
575 IN EFI_EVENT Event OPTIONAL
581 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
582 Status
= LsiScsiCheckRequest (Dev
, *Target
, Lun
, Packet
);
583 if (EFI_ERROR (Status
)) {
587 return LsiScsiProcessRequest (Dev
, *Target
, Lun
, Packet
);
592 LsiScsiGetNextTargetLun (
593 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
594 IN OUT UINT8
**TargetPointer
,
604 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
606 Target
= *TargetPointer
;
609 // Search for first non-0xFF byte. If not found, return first target & LUN.
611 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
&& Target
[Idx
] == 0xFF; ++Idx
) {
614 if (Idx
== TARGET_MAX_BYTES
) {
615 SetMem (Target
, TARGET_MAX_BYTES
, 0x00);
620 CopyMem (&LastTarget
, Target
, sizeof LastTarget
);
623 // increment (target, LUN) pair if valid on input
625 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
626 if ((LastTarget
> Dev
->MaxTarget
) || (*Lun
> Dev
->MaxLun
)) {
627 return EFI_INVALID_PARAMETER
;
630 if (*Lun
< Dev
->MaxLun
) {
635 if (LastTarget
< Dev
->MaxTarget
) {
638 CopyMem (Target
, &LastTarget
, sizeof LastTarget
);
642 return EFI_NOT_FOUND
;
647 LsiScsiBuildDevicePath (
648 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
651 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
656 SCSI_DEVICE_PATH
*ScsiDevicePath
;
658 if (DevicePath
== NULL
) {
659 return EFI_INVALID_PARAMETER
;
662 CopyMem (&TargetValue
, Target
, sizeof TargetValue
);
663 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
664 if ((TargetValue
> Dev
->MaxTarget
) || (Lun
> Dev
->MaxLun
) || (Lun
> 0xFFFF)) {
665 return EFI_NOT_FOUND
;
668 ScsiDevicePath
= AllocatePool (sizeof *ScsiDevicePath
);
669 if (ScsiDevicePath
== NULL
) {
670 return EFI_OUT_OF_RESOURCES
;
673 ScsiDevicePath
->Header
.Type
= MESSAGING_DEVICE_PATH
;
674 ScsiDevicePath
->Header
.SubType
= MSG_SCSI_DP
;
675 ScsiDevicePath
->Header
.Length
[0] = (UINT8
)sizeof *ScsiDevicePath
;
676 ScsiDevicePath
->Header
.Length
[1] = (UINT8
)(sizeof *ScsiDevicePath
>> 8);
677 ScsiDevicePath
->Pun
= TargetValue
;
678 ScsiDevicePath
->Lun
= (UINT16
)Lun
;
680 *DevicePath
= &ScsiDevicePath
->Header
;
686 LsiScsiGetTargetLun (
687 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
688 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
689 OUT UINT8
**TargetPointer
,
693 SCSI_DEVICE_PATH
*ScsiDevicePath
;
697 if ((DevicePath
== NULL
) || (TargetPointer
== NULL
) || (*TargetPointer
== NULL
) ||
700 return EFI_INVALID_PARAMETER
;
703 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
704 (DevicePath
->SubType
!= MSG_SCSI_DP
))
706 return EFI_UNSUPPORTED
;
709 ScsiDevicePath
= (SCSI_DEVICE_PATH
*)DevicePath
;
710 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
711 if ((ScsiDevicePath
->Pun
> Dev
->MaxTarget
) ||
712 (ScsiDevicePath
->Lun
> Dev
->MaxLun
))
714 return EFI_NOT_FOUND
;
717 Target
= *TargetPointer
;
718 ZeroMem (Target
, TARGET_MAX_BYTES
);
719 CopyMem (Target
, &ScsiDevicePath
->Pun
, sizeof ScsiDevicePath
->Pun
);
720 *Lun
= ScsiDevicePath
->Lun
;
727 LsiScsiResetChannel (
728 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
731 return EFI_UNSUPPORTED
;
736 LsiScsiResetTargetLun (
737 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
742 return EFI_UNSUPPORTED
;
747 LsiScsiGetNextTarget (
748 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
749 IN OUT UINT8
**TargetPointer
758 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
760 Target
= *TargetPointer
;
763 // Search for first non-0xFF byte. If not found, return first target.
765 for (Idx
= 0; Idx
< TARGET_MAX_BYTES
&& Target
[Idx
] == 0xFF; ++Idx
) {
768 if (Idx
== TARGET_MAX_BYTES
) {
769 SetMem (Target
, TARGET_MAX_BYTES
, 0x00);
773 CopyMem (&LastTarget
, Target
, sizeof LastTarget
);
776 // increment target if valid on input
778 Dev
= LSI_SCSI_FROM_PASS_THRU (This
);
779 if (LastTarget
> Dev
->MaxTarget
) {
780 return EFI_INVALID_PARAMETER
;
783 if (LastTarget
< Dev
->MaxTarget
) {
785 CopyMem (Target
, &LastTarget
, sizeof LastTarget
);
789 return EFI_NOT_FOUND
;
803 DEBUG ((DEBUG_VERBOSE
, "%a: Context=0x%p\n", __FUNCTION__
, Context
));
808 // Probe, start and stop functions of this driver, called by the DXE core for
811 // The following specifications document these interfaces:
812 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
813 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
818 LsiScsiControllerSupported (
819 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
820 IN EFI_HANDLE ControllerHandle
,
821 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
825 EFI_PCI_IO_PROTOCOL
*PciIo
;
828 Status
= gBS
->OpenProtocol (
830 &gEfiPciIoProtocolGuid
,
832 This
->DriverBindingHandle
,
834 EFI_OPEN_PROTOCOL_BY_DRIVER
836 if (EFI_ERROR (Status
)) {
840 Status
= PciIo
->Pci
.Read (
844 sizeof (Pci
) / sizeof (UINT32
),
847 if (EFI_ERROR (Status
)) {
851 if ((Pci
.Hdr
.VendorId
== LSI_LOGIC_PCI_VENDOR_ID
) &&
852 (Pci
.Hdr
.DeviceId
== LSI_53C895A_PCI_DEVICE_ID
))
854 Status
= EFI_SUCCESS
;
856 Status
= EFI_UNSUPPORTED
;
862 &gEfiPciIoProtocolGuid
,
863 This
->DriverBindingHandle
,
871 LsiScsiControllerStart (
872 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
873 IN EFI_HANDLE ControllerHandle
,
874 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
882 Dev
= AllocateZeroPool (sizeof (*Dev
));
884 return EFI_OUT_OF_RESOURCES
;
887 Dev
->Signature
= LSI_SCSI_DEV_SIGNATURE
;
890 FixedPcdGet8 (PcdLsiScsiMaxTargetLimit
) < 8,
891 "LSI 53C895A supports targets [0..7]"
894 FixedPcdGet8 (PcdLsiScsiMaxLunLimit
) < 128,
895 "LSI 53C895A supports LUNs [0..127]"
897 Dev
->MaxTarget
= PcdGet8 (PcdLsiScsiMaxTargetLimit
);
898 Dev
->MaxLun
= PcdGet8 (PcdLsiScsiMaxLunLimit
);
899 Dev
->StallPerPollUsec
= PcdGet32 (PcdLsiScsiStallPerPollUsec
);
901 Status
= gBS
->OpenProtocol (
903 &gEfiPciIoProtocolGuid
,
904 (VOID
**)&Dev
->PciIo
,
905 This
->DriverBindingHandle
,
907 EFI_OPEN_PROTOCOL_BY_DRIVER
909 if (EFI_ERROR (Status
)) {
913 Status
= Dev
->PciIo
->Attributes (
915 EfiPciIoAttributeOperationGet
,
919 if (EFI_ERROR (Status
)) {
924 // Enable I/O Space & Bus-Mastering
926 Status
= Dev
->PciIo
->Attributes (
928 EfiPciIoAttributeOperationEnable
,
929 (EFI_PCI_IO_ATTRIBUTE_IO
|
930 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
933 if (EFI_ERROR (Status
)) {
938 // Create buffers for data transfer
940 Pages
= EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
));
941 Status
= Dev
->PciIo
->AllocateBuffer (
947 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
949 if (EFI_ERROR (Status
)) {
950 goto RestoreAttributes
;
953 BytesMapped
= EFI_PAGES_TO_SIZE (Pages
);
954 Status
= Dev
->PciIo
->Map (
956 EfiPciIoOperationBusMasterCommonBuffer
,
962 if (EFI_ERROR (Status
)) {
966 if (BytesMapped
!= EFI_PAGES_TO_SIZE (Pages
)) {
967 Status
= EFI_OUT_OF_RESOURCES
;
971 Status
= LsiScsiReset (Dev
);
972 if (EFI_ERROR (Status
)) {
976 Status
= gBS
->CreateEvent (
977 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
983 if (EFI_ERROR (Status
)) {
988 // Host adapter channel, doesn't exist
990 Dev
->PassThruMode
.AdapterId
= MAX_UINT32
;
991 Dev
->PassThruMode
.Attributes
=
992 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
993 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
995 Dev
->PassThru
.Mode
= &Dev
->PassThruMode
;
996 Dev
->PassThru
.PassThru
= &LsiScsiPassThru
;
997 Dev
->PassThru
.GetNextTargetLun
= &LsiScsiGetNextTargetLun
;
998 Dev
->PassThru
.BuildDevicePath
= &LsiScsiBuildDevicePath
;
999 Dev
->PassThru
.GetTargetLun
= &LsiScsiGetTargetLun
;
1000 Dev
->PassThru
.ResetChannel
= &LsiScsiResetChannel
;
1001 Dev
->PassThru
.ResetTargetLun
= &LsiScsiResetTargetLun
;
1002 Dev
->PassThru
.GetNextTarget
= &LsiScsiGetNextTarget
;
1004 Status
= gBS
->InstallProtocolInterface (
1006 &gEfiExtScsiPassThruProtocolGuid
,
1007 EFI_NATIVE_INTERFACE
,
1010 if (EFI_ERROR (Status
)) {
1017 gBS
->CloseEvent (Dev
->ExitBoot
);
1029 Dev
->PciIo
->FreeBuffer (
1036 Dev
->PciIo
->Attributes (
1038 EfiPciIoAttributeOperationSet
,
1044 gBS
->CloseProtocol (
1046 &gEfiPciIoProtocolGuid
,
1047 This
->DriverBindingHandle
,
1059 LsiScsiControllerStop (
1060 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1061 IN EFI_HANDLE ControllerHandle
,
1062 IN UINTN NumberOfChildren
,
1063 IN EFI_HANDLE
*ChildHandleBuffer
1067 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
1070 Status
= gBS
->OpenProtocol (
1072 &gEfiExtScsiPassThruProtocolGuid
,
1074 This
->DriverBindingHandle
,
1076 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// Lookup only
1078 if (EFI_ERROR (Status
)) {
1082 Dev
= LSI_SCSI_FROM_PASS_THRU (PassThru
);
1084 Status
= gBS
->UninstallProtocolInterface (
1086 &gEfiExtScsiPassThruProtocolGuid
,
1089 if (EFI_ERROR (Status
)) {
1093 gBS
->CloseEvent (Dev
->ExitBoot
);
1102 Dev
->PciIo
->FreeBuffer (
1104 EFI_SIZE_TO_PAGES (sizeof (*Dev
->Dma
)),
1108 Dev
->PciIo
->Attributes (
1110 EfiPciIoAttributeOperationSet
,
1115 gBS
->CloseProtocol (
1117 &gEfiPciIoProtocolGuid
,
1118 This
->DriverBindingHandle
,
1128 // The static object that groups the Supported() (ie. probe), Start() and
1129 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
1130 // C, 10.1 EFI Driver Binding Protocol.
1133 EFI_DRIVER_BINDING_PROTOCOL gDriverBinding
= {
1134 &LsiScsiControllerSupported
,
1135 &LsiScsiControllerStart
,
1136 &LsiScsiControllerStop
,
1137 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1138 NULL
, // ImageHandle, to be overwritten by
1139 // EfiLibInstallDriverBindingComponentName2() in LsiScsiEntryPoint()
1140 NULL
// DriverBindingHandle, ditto
1144 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
1145 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
1146 // in English, for display on standard console devices. This is recommended for
1147 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
1148 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
1150 // Device type names ("LSI 53C895A SCSI Controller") are not formatted because
1151 // the driver supports only that device type. Therefore the driver name
1152 // suffices for unambiguous identification.
1156 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1157 { "eng;en", L
"LSI 53C895A SCSI Controller Driver" },
1162 EFI_COMPONENT_NAME_PROTOCOL gComponentName
;
1166 LsiScsiGetDriverName (
1167 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1169 OUT CHAR16
**DriverName
1172 return LookupUnicodeString2 (
1174 This
->SupportedLanguages
,
1177 (BOOLEAN
)(This
== &gComponentName
) // Iso639Language
1183 LsiScsiGetDeviceName (
1184 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1185 IN EFI_HANDLE DeviceHandle
,
1186 IN EFI_HANDLE ChildHandle
,
1188 OUT CHAR16
**ControllerName
1191 return EFI_UNSUPPORTED
;
1195 EFI_COMPONENT_NAME_PROTOCOL gComponentName
= {
1196 &LsiScsiGetDriverName
,
1197 &LsiScsiGetDeviceName
,
1198 "eng" // SupportedLanguages, ISO 639-2 language codes
1202 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2
= {
1203 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
)&LsiScsiGetDriverName
,
1204 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
)&LsiScsiGetDeviceName
,
1205 "en" // SupportedLanguages, RFC 4646 language codes
1209 // Entry point of this driver
1214 IN EFI_HANDLE ImageHandle
,
1215 IN EFI_SYSTEM_TABLE
*SystemTable
1218 return EfiLibInstallDriverBindingComponentName2 (
1222 ImageHandle
, // The handle to install onto