12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226 |
- /** @file
- This driver produces Extended SCSI Pass Thru Protocol instances for
- LSI 53C895A SCSI devices.
- Copyright (C) 2020, SUSE LLC.
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <IndustryStandard/LsiScsi.h>
- #include <IndustryStandard/Pci.h>
- #include <Library/BaseLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/PcdLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/UefiLib.h>
- #include <Protocol/PciIo.h>
- #include <Protocol/PciRootBridgeIo.h>
- #include <Protocol/ScsiPassThruExt.h>
- #include <Uefi/UefiSpec.h>
- #include "LsiScsi.h"
- STATIC
- EFI_STATUS
- Out8 (
- IN LSI_SCSI_DEV *Dev,
- IN UINT32 Addr,
- IN UINT8 Data
- )
- {
- return Dev->PciIo->Io.Write (
- Dev->PciIo,
- EfiPciIoWidthUint8,
- PCI_BAR_IDX0,
- Addr,
- 1,
- &Data
- );
- }
- STATIC
- EFI_STATUS
- Out32 (
- IN LSI_SCSI_DEV *Dev,
- IN UINT32 Addr,
- IN UINT32 Data
- )
- {
- return Dev->PciIo->Io.Write (
- Dev->PciIo,
- EfiPciIoWidthUint32,
- PCI_BAR_IDX0,
- Addr,
- 1,
- &Data
- );
- }
- STATIC
- EFI_STATUS
- In8 (
- IN LSI_SCSI_DEV *Dev,
- IN UINT32 Addr,
- OUT UINT8 *Data
- )
- {
- return Dev->PciIo->Io.Read (
- Dev->PciIo,
- EfiPciIoWidthUint8,
- PCI_BAR_IDX0,
- Addr,
- 1,
- Data
- );
- }
- STATIC
- EFI_STATUS
- In32 (
- IN LSI_SCSI_DEV *Dev,
- IN UINT32 Addr,
- OUT UINT32 *Data
- )
- {
- return Dev->PciIo->Io.Read (
- Dev->PciIo,
- EfiPciIoWidthUint32,
- PCI_BAR_IDX0,
- Addr,
- 1,
- Data
- );
- }
- STATIC
- EFI_STATUS
- LsiScsiReset (
- IN LSI_SCSI_DEV *Dev
- )
- {
- return Out8 (Dev, LSI_REG_ISTAT0, LSI_ISTAT0_SRST);
- }
- STATIC
- EFI_STATUS
- ReportHostAdapterOverrunError (
- OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- Packet->SenseDataLength = 0;
- Packet->HostAdapterStatus =
- EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
- Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
- return EFI_BAD_BUFFER_SIZE;
- }
- /**
- Check the request packet from the Extended SCSI Pass Thru Protocol. The
- request packet is modified, to be forwarded outwards by LsiScsiPassThru(),
- if invalid or unsupported parameters are detected.
- @param[in] Dev The LSI 53C895A SCSI device the packet targets.
- @param[in] Target The SCSI target controlled by the LSI 53C895A SCSI
- device.
- @param[in] Lun The Logical Unit Number under the SCSI target.
- @param[in out] Packet The Extended SCSI Pass Thru Protocol packet.
- @retval EFI_SUCCESS The Extended SCSI Pass Thru Protocol packet was valid.
- @return Otherwise, invalid or unsupported parameters were
- detected. Status codes are meant for direct forwarding
- by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
- implementation.
- **/
- STATIC
- EFI_STATUS
- LsiScsiCheckRequest (
- IN LSI_SCSI_DEV *Dev,
- IN UINT8 Target,
- IN UINT64 Lun,
- IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- if ((Target > Dev->MaxTarget) || (Lun > Dev->MaxLun) ||
- (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
- //
- // Trying to receive, but destination pointer is NULL, or contradicting
- // transfer direction
- //
- ((Packet->InTransferLength > 0) &&
- ((Packet->InDataBuffer == NULL) ||
- (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
- )
- ) ||
- //
- // Trying to send, but source pointer is NULL, or contradicting transfer
- // direction
- //
- ((Packet->OutTransferLength > 0) &&
- ((Packet->OutDataBuffer == NULL) ||
- (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
- )
- )
- )
- {
- return EFI_INVALID_PARAMETER;
- }
- if ((Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
- ((Packet->InTransferLength > 0) && (Packet->OutTransferLength > 0)) ||
- (Packet->CdbLength > sizeof Dev->Dma->Cdb))
- {
- return EFI_UNSUPPORTED;
- }
- if (Packet->InTransferLength > sizeof Dev->Dma->Data) {
- Packet->InTransferLength = sizeof Dev->Dma->Data;
- return ReportHostAdapterOverrunError (Packet);
- }
- if (Packet->OutTransferLength > sizeof Dev->Dma->Data) {
- Packet->OutTransferLength = sizeof Dev->Dma->Data;
- return ReportHostAdapterOverrunError (Packet);
- }
- return EFI_SUCCESS;
- }
- /**
- Interpret the request packet from the Extended SCSI Pass Thru Protocol and
- compose the script to submit the command and data to the controller.
- @param[in] Dev The LSI 53C895A SCSI device the packet targets.
- @param[in] Target The SCSI target controlled by the LSI 53C895A SCSI
- device.
- @param[in] Lun The Logical Unit Number under the SCSI target.
- @param[in out] Packet The Extended SCSI Pass Thru Protocol packet.
- @retval EFI_SUCCESS The Extended SCSI Pass Thru Protocol packet was valid.
- @return Otherwise, invalid or unsupported parameters were
- detected. Status codes are meant for direct forwarding
- by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
- implementation.
- **/
- STATIC
- EFI_STATUS
- LsiScsiProcessRequest (
- IN LSI_SCSI_DEV *Dev,
- IN UINT8 Target,
- IN UINT64 Lun,
- IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- EFI_STATUS Status;
- UINT32 *Script;
- UINT8 *Cdb;
- UINT8 *MsgOut;
- UINT8 *MsgIn;
- UINT8 *ScsiStatus;
- UINT8 *Data;
- UINT8 DStat;
- UINT8 SIst0;
- UINT8 SIst1;
- UINT32 Csbc;
- UINT32 CsbcBase;
- UINT32 Transferred;
- Script = Dev->Dma->Script;
- Cdb = Dev->Dma->Cdb;
- Data = Dev->Dma->Data;
- MsgIn = Dev->Dma->MsgIn;
- MsgOut = &Dev->Dma->MsgOut;
- ScsiStatus = &Dev->Dma->Status;
- *ScsiStatus = 0xFF;
- DStat = 0;
- SIst0 = 0;
- SIst1 = 0;
- SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
- CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
- //
- // Fetch the first Cumulative SCSI Byte Count (CSBC).
- //
- // CSBC is a cumulative counter of the actual number of bytes that have been
- // transferred across the SCSI bus during data phases, i.e. it will not
- // count bytes sent in command, status, message in and out phases.
- //
- Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- //
- // Clean up the DMA buffer for the script.
- //
- SetMem (Script, sizeof Dev->Dma->Script, 0x00);
- //
- // Compose the script to transfer data between the host and the device.
- //
- // References:
- // * LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2
- // - Chapter 5 SCSI SCRIPT Instruction Set
- // * SEABIOS lsi-scsi driver
- //
- // All instructions used here consist of 2 32bit words. The first word
- // contains the command to execute. The second word is loaded into the
- // DMA SCRIPTS Pointer Save (DSPS) register as either the DMA address
- // for data transmission or the address/offset for the jump command.
- // Some commands, such as the selection of the target, don't need to
- // transfer data through DMA or jump to another instruction, then DSPS
- // has to be zero.
- //
- // There are 3 major parts in this script. The first part (1~3) contains
- // the instructions to select target and LUN and send the SCSI command
- // from the request packet. The second part (4~7) is to handle the
- // potential disconnection and prepare for the data transmission. The
- // instructions in the third part (8~10) transmit the given data and
- // collect the result. Instruction 11 raises the interrupt and marks the
- // end of the script.
- //
- //
- // 1. Select target.
- //
- *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_SEL | (UINT32)Target << 16;
- *Script++ = 0x00000000;
- //
- // 2. Select LUN.
- //
- *MsgOut = 0x80 | (UINT8)Lun; // 0x80: Identify bit
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_OUT |
- (UINT32)sizeof Dev->Dma->MsgOut;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgOut);
- //
- // 3. Send the SCSI Command.
- //
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_CMD |
- (UINT32)sizeof Dev->Dma->Cdb;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, Cdb);
- //
- // 4. Check whether the current SCSI phase is "Message In" or not
- // and jump to 7 if it is.
- // Note: LSI_INS_TC_RA stands for "Relative Address Mode", so the
- // offset 0x18 in the second word means jumping forward
- // 3 (0x18/8) instructions.
- //
- *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_JMP |
- LSI_INS_TC_SCSIP_MSG_IN | LSI_INS_TC_RA |
- LSI_INS_TC_CP;
- *Script++ = 0x00000018;
- //
- // 5. Read "Message" from the initiator to trigger reselect.
- //
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
- (UINT32)sizeof Dev->Dma->MsgIn;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
- //
- // 6. Wait reselect.
- //
- *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_WAIT_RESEL;
- *Script++ = 0x00000000;
- //
- // 7. Read "Message" from the initiator again
- //
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
- (UINT32)sizeof Dev->Dma->MsgIn;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
- //
- // 8. Set the DMA command for the read/write operations.
- // Note: Some requests, e.g. "TEST UNIT READY", do not come with
- // allocated InDataBuffer or OutDataBuffer. We skip the DMA
- // data command for those requests or this script would fail
- // with LSI_SIST0_SGE due to the zero data length.
- //
- // LsiScsiCheckRequest() prevents both integer overflows in the command
- // opcodes, and buffer overflows.
- //
- if (Packet->InTransferLength > 0) {
- ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ);
- ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_IN |
- Packet->InTransferLength;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
- } else if (Packet->OutTransferLength > 0) {
- ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE);
- ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);
- CopyMem (Data, Packet->OutDataBuffer, Packet->OutTransferLength);
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_OUT |
- Packet->OutTransferLength;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
- }
- //
- // 9. Get the SCSI status.
- //
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_STAT |
- (UINT32)sizeof Dev->Dma->Status;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, Status);
- //
- // 10. Get the SCSI message.
- //
- *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
- (UINT32)sizeof Dev->Dma->MsgIn;
- *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
- //
- // 11. Raise the interrupt to end the script.
- //
- *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_INT |
- LSI_INS_TC_SCSIP_DAT_OUT | LSI_INS_TC_JMP;
- *Script++ = 0x00000000;
- //
- // Make sure the size of the script doesn't exceed the buffer.
- //
- ASSERT (Script <= Dev->Dma->Script + ARRAY_SIZE (Dev->Dma->Script));
- //
- // The controller starts to execute the script once the DMA Script
- // Pointer (DSP) register is set.
- //
- Status = Out32 (Dev, LSI_REG_DSP, LSI_SCSI_DMA_ADDR (Dev, Script));
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- //
- // Poll the device registers (DSTAT, SIST0, and SIST1) until the SIR
- // bit sets.
- //
- for ( ; ;) {
- Status = In8 (Dev, LSI_REG_DSTAT, &DStat);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- Status = In8 (Dev, LSI_REG_SIST0, &SIst0);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- Status = In8 (Dev, LSI_REG_SIST1, &SIst1);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- if ((SIst0 != 0) || (SIst1 != 0)) {
- goto Error;
- }
- //
- // Check the SIR (SCRIPTS Interrupt Instruction Received) bit.
- //
- if (DStat & LSI_DSTAT_SIR) {
- break;
- }
- gBS->Stall (Dev->StallPerPollUsec);
- }
- //
- // Check if everything is good.
- // SCSI Message Code 0x00: COMMAND COMPLETE
- // SCSI Status Code 0x00: Good
- //
- if ((MsgIn[0] != 0) || (*ScsiStatus != 0)) {
- goto Error;
- }
- //
- // Fetch CSBC again to calculate the transferred bytes and update
- // InTransferLength/OutTransferLength.
- //
- // Note: The number of transferred bytes is bounded by
- // "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase
- // from Csbc. If the CSBC register wraps around, the correct
- // difference is ensured by the standard C modular arithmetic.
- //
- Status = In32 (Dev, LSI_REG_CSBC, &Csbc);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- Transferred = Csbc - CsbcBase;
- if (Packet->InTransferLength > 0) {
- if (Transferred <= Packet->InTransferLength) {
- Packet->InTransferLength = Transferred;
- } else {
- goto Error;
- }
- } else if (Packet->OutTransferLength > 0) {
- if (Transferred <= Packet->OutTransferLength) {
- Packet->OutTransferLength = Transferred;
- } else {
- goto Error;
- }
- }
- //
- // Copy Data to InDataBuffer if necessary.
- //
- if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
- CopyMem (Packet->InDataBuffer, Data, Packet->InTransferLength);
- }
- //
- // Always set SenseDataLength to 0.
- // The instructions of LSI53C895A don't reply sense data. Instead, it
- // relies on the SCSI command, "REQUEST SENSE", to get sense data. We set
- // SenseDataLength to 0 to notify ScsiDiskDxe that there is no sense data
- // written even if this request is processed successfully, so that It will
- // issue "REQUEST SENSE" later to retrieve sense data.
- //
- Packet->SenseDataLength = 0;
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
- Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
- return EFI_SUCCESS;
- Error:
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: dstat: %02X, sist0: %02X, sist1: %02X\n",
- __FUNCTION__,
- DStat,
- SIst0,
- SIst1
- ));
- //
- // Update the request packet to reflect the status.
- //
- if (*ScsiStatus != 0xFF) {
- Packet->TargetStatus = *ScsiStatus;
- } else {
- Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
- }
- if (SIst0 & LSI_SIST0_PAR) {
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
- } else if (SIst0 & LSI_SIST0_RST) {
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
- } else if (SIst0 & LSI_SIST0_UDC) {
- //
- // The target device is disconnected unexpectedly. According to UEFI spec,
- // this is TIMEOUT_COMMAND.
- //
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
- } else if (SIst0 & LSI_SIST0_SGE) {
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
- } else if (SIst1 & LSI_SIST1_HTH) {
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
- } else if (SIst1 & LSI_SIST1_GEN) {
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
- } else if (SIst1 & LSI_SIST1_STO) {
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
- } else {
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
- }
- //
- // SenseData may be used to inspect the error. Since we don't set sense data,
- // SenseDataLength has to be 0.
- //
- Packet->SenseDataLength = 0;
- return EFI_DEVICE_ERROR;
- }
- //
- // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
- // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
- // sections
- // - 14.1 SCSI Driver Model Overview,
- // - 14.7 Extended SCSI Pass Thru Protocol.
- //
- EFI_STATUS
- EFIAPI
- LsiScsiPassThru (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN UINT8 *Target,
- IN UINT64 Lun,
- IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
- IN EFI_EVENT Event OPTIONAL
- )
- {
- EFI_STATUS Status;
- LSI_SCSI_DEV *Dev;
- Dev = LSI_SCSI_FROM_PASS_THRU (This);
- Status = LsiScsiCheckRequest (Dev, *Target, Lun, Packet);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- return LsiScsiProcessRequest (Dev, *Target, Lun, Packet);
- }
- EFI_STATUS
- EFIAPI
- LsiScsiGetNextTargetLun (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN OUT UINT8 **TargetPointer,
- IN OUT UINT64 *Lun
- )
- {
- LSI_SCSI_DEV *Dev;
- UINTN Idx;
- UINT8 *Target;
- UINT16 LastTarget;
- //
- // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
- //
- Target = *TargetPointer;
- //
- // Search for first non-0xFF byte. If not found, return first target & LUN.
- //
- for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx) {
- }
- if (Idx == TARGET_MAX_BYTES) {
- SetMem (Target, TARGET_MAX_BYTES, 0x00);
- *Lun = 0;
- return EFI_SUCCESS;
- }
- CopyMem (&LastTarget, Target, sizeof LastTarget);
- //
- // increment (target, LUN) pair if valid on input
- //
- Dev = LSI_SCSI_FROM_PASS_THRU (This);
- if ((LastTarget > Dev->MaxTarget) || (*Lun > Dev->MaxLun)) {
- return EFI_INVALID_PARAMETER;
- }
- if (*Lun < Dev->MaxLun) {
- ++*Lun;
- return EFI_SUCCESS;
- }
- if (LastTarget < Dev->MaxTarget) {
- *Lun = 0;
- ++LastTarget;
- CopyMem (Target, &LastTarget, sizeof LastTarget);
- return EFI_SUCCESS;
- }
- return EFI_NOT_FOUND;
- }
- EFI_STATUS
- EFIAPI
- LsiScsiBuildDevicePath (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN UINT8 *Target,
- IN UINT64 Lun,
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
- )
- {
- UINT16 TargetValue;
- LSI_SCSI_DEV *Dev;
- SCSI_DEVICE_PATH *ScsiDevicePath;
- if (DevicePath == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- CopyMem (&TargetValue, Target, sizeof TargetValue);
- Dev = LSI_SCSI_FROM_PASS_THRU (This);
- if ((TargetValue > Dev->MaxTarget) || (Lun > Dev->MaxLun) || (Lun > 0xFFFF)) {
- return EFI_NOT_FOUND;
- }
- ScsiDevicePath = AllocatePool (sizeof *ScsiDevicePath);
- if (ScsiDevicePath == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
- ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
- ScsiDevicePath->Header.Length[0] = (UINT8)sizeof *ScsiDevicePath;
- ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof *ScsiDevicePath >> 8);
- ScsiDevicePath->Pun = TargetValue;
- ScsiDevicePath->Lun = (UINT16)Lun;
- *DevicePath = &ScsiDevicePath->Header;
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- LsiScsiGetTargetLun (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT UINT8 **TargetPointer,
- OUT UINT64 *Lun
- )
- {
- SCSI_DEVICE_PATH *ScsiDevicePath;
- LSI_SCSI_DEV *Dev;
- UINT8 *Target;
- if ((DevicePath == NULL) || (TargetPointer == NULL) || (*TargetPointer == NULL) ||
- (Lun == NULL))
- {
- return EFI_INVALID_PARAMETER;
- }
- if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
- (DevicePath->SubType != MSG_SCSI_DP))
- {
- return EFI_UNSUPPORTED;
- }
- ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
- Dev = LSI_SCSI_FROM_PASS_THRU (This);
- if ((ScsiDevicePath->Pun > Dev->MaxTarget) ||
- (ScsiDevicePath->Lun > Dev->MaxLun))
- {
- return EFI_NOT_FOUND;
- }
- Target = *TargetPointer;
- ZeroMem (Target, TARGET_MAX_BYTES);
- CopyMem (Target, &ScsiDevicePath->Pun, sizeof ScsiDevicePath->Pun);
- *Lun = ScsiDevicePath->Lun;
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- LsiScsiResetChannel (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
- )
- {
- return EFI_UNSUPPORTED;
- }
- EFI_STATUS
- EFIAPI
- LsiScsiResetTargetLun (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN UINT8 *Target,
- IN UINT64 Lun
- )
- {
- return EFI_UNSUPPORTED;
- }
- EFI_STATUS
- EFIAPI
- LsiScsiGetNextTarget (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN OUT UINT8 **TargetPointer
- )
- {
- LSI_SCSI_DEV *Dev;
- UINTN Idx;
- UINT8 *Target;
- UINT16 LastTarget;
- //
- // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
- //
- Target = *TargetPointer;
- //
- // Search for first non-0xFF byte. If not found, return first target.
- //
- for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx) {
- }
- if (Idx == TARGET_MAX_BYTES) {
- SetMem (Target, TARGET_MAX_BYTES, 0x00);
- return EFI_SUCCESS;
- }
- CopyMem (&LastTarget, Target, sizeof LastTarget);
- //
- // increment target if valid on input
- //
- Dev = LSI_SCSI_FROM_PASS_THRU (This);
- if (LastTarget > Dev->MaxTarget) {
- return EFI_INVALID_PARAMETER;
- }
- if (LastTarget < Dev->MaxTarget) {
- ++LastTarget;
- CopyMem (Target, &LastTarget, sizeof LastTarget);
- return EFI_SUCCESS;
- }
- return EFI_NOT_FOUND;
- }
- STATIC
- VOID
- EFIAPI
- LsiScsiExitBoot (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- LSI_SCSI_DEV *Dev;
- Dev = Context;
- DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
- LsiScsiReset (Dev);
- }
- //
- // Probe, start and stop functions of this driver, called by the DXE core for
- // specific devices.
- //
- // The following specifications document these interfaces:
- // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
- // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
- //
- EFI_STATUS
- EFIAPI
- LsiScsiControllerSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- EFI_PCI_IO_PROTOCOL *PciIo;
- PCI_TYPE00 Pci;
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- (VOID **)&PciIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = PciIo->Pci.Read (
- PciIo,
- EfiPciIoWidthUint32,
- 0,
- sizeof (Pci) / sizeof (UINT32),
- &Pci
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- if ((Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID) &&
- (Pci.Hdr.DeviceId == LSI_53C895A_PCI_DEVICE_ID))
- {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_UNSUPPORTED;
- }
- Done:
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- return Status;
- }
- EFI_STATUS
- EFIAPI
- LsiScsiControllerStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- LSI_SCSI_DEV *Dev;
- UINTN Pages;
- UINTN BytesMapped;
- Dev = AllocateZeroPool (sizeof (*Dev));
- if (Dev == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Dev->Signature = LSI_SCSI_DEV_SIGNATURE;
- STATIC_ASSERT (
- FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8,
- "LSI 53C895A supports targets [0..7]"
- );
- STATIC_ASSERT (
- FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128,
- "LSI 53C895A supports LUNs [0..127]"
- );
- Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
- Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
- Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- (VOID **)&Dev->PciIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- goto FreePool;
- }
- Status = Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationGet,
- 0,
- &Dev->OrigPciAttrs
- );
- if (EFI_ERROR (Status)) {
- goto CloseProtocol;
- }
- //
- // Enable I/O Space & Bus-Mastering
- //
- Status = Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationEnable,
- (EFI_PCI_IO_ATTRIBUTE_IO |
- EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
- NULL
- );
- if (EFI_ERROR (Status)) {
- goto CloseProtocol;
- }
- //
- // Create buffers for data transfer
- //
- Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));
- Status = Dev->PciIo->AllocateBuffer (
- Dev->PciIo,
- AllocateAnyPages,
- EfiBootServicesData,
- Pages,
- (VOID **)&Dev->Dma,
- EFI_PCI_ATTRIBUTE_MEMORY_CACHED
- );
- if (EFI_ERROR (Status)) {
- goto RestoreAttributes;
- }
- BytesMapped = EFI_PAGES_TO_SIZE (Pages);
- Status = Dev->PciIo->Map (
- Dev->PciIo,
- EfiPciIoOperationBusMasterCommonBuffer,
- Dev->Dma,
- &BytesMapped,
- &Dev->DmaPhysical,
- &Dev->DmaMapping
- );
- if (EFI_ERROR (Status)) {
- goto FreeBuffer;
- }
- if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Unmap;
- }
- Status = LsiScsiReset (Dev);
- if (EFI_ERROR (Status)) {
- goto Unmap;
- }
- Status = gBS->CreateEvent (
- EVT_SIGNAL_EXIT_BOOT_SERVICES,
- TPL_CALLBACK,
- &LsiScsiExitBoot,
- Dev,
- &Dev->ExitBoot
- );
- if (EFI_ERROR (Status)) {
- goto UninitDev;
- }
- //
- // Host adapter channel, doesn't exist
- //
- Dev->PassThruMode.AdapterId = MAX_UINT32;
- Dev->PassThruMode.Attributes =
- EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
- EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
- Dev->PassThru.Mode = &Dev->PassThruMode;
- Dev->PassThru.PassThru = &LsiScsiPassThru;
- Dev->PassThru.GetNextTargetLun = &LsiScsiGetNextTargetLun;
- Dev->PassThru.BuildDevicePath = &LsiScsiBuildDevicePath;
- Dev->PassThru.GetTargetLun = &LsiScsiGetTargetLun;
- Dev->PassThru.ResetChannel = &LsiScsiResetChannel;
- Dev->PassThru.ResetTargetLun = &LsiScsiResetTargetLun;
- Dev->PassThru.GetNextTarget = &LsiScsiGetNextTarget;
- Status = gBS->InstallProtocolInterface (
- &ControllerHandle,
- &gEfiExtScsiPassThruProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &Dev->PassThru
- );
- if (EFI_ERROR (Status)) {
- goto CloseExitBoot;
- }
- return EFI_SUCCESS;
- CloseExitBoot:
- gBS->CloseEvent (Dev->ExitBoot);
- UninitDev:
- LsiScsiReset (Dev);
- Unmap:
- Dev->PciIo->Unmap (
- Dev->PciIo,
- Dev->DmaMapping
- );
- FreeBuffer:
- Dev->PciIo->FreeBuffer (
- Dev->PciIo,
- Pages,
- Dev->Dma
- );
- RestoreAttributes:
- Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationSet,
- Dev->OrigPciAttrs,
- NULL
- );
- CloseProtocol:
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- FreePool:
- FreePool (Dev);
- return Status;
- }
- EFI_STATUS
- EFIAPI
- LsiScsiControllerStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
- )
- {
- EFI_STATUS Status;
- EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
- LSI_SCSI_DEV *Dev;
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiExtScsiPassThruProtocolGuid,
- (VOID **)&PassThru,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Dev = LSI_SCSI_FROM_PASS_THRU (PassThru);
- Status = gBS->UninstallProtocolInterface (
- ControllerHandle,
- &gEfiExtScsiPassThruProtocolGuid,
- &Dev->PassThru
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- gBS->CloseEvent (Dev->ExitBoot);
- LsiScsiReset (Dev);
- Dev->PciIo->Unmap (
- Dev->PciIo,
- Dev->DmaMapping
- );
- Dev->PciIo->FreeBuffer (
- Dev->PciIo,
- EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),
- Dev->Dma
- );
- Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationSet,
- Dev->OrigPciAttrs,
- NULL
- );
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- FreePool (Dev);
- return Status;
- }
- //
- // The static object that groups the Supported() (ie. probe), Start() and
- // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
- // C, 10.1 EFI Driver Binding Protocol.
- //
- STATIC
- EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
- &LsiScsiControllerSupported,
- &LsiScsiControllerStart,
- &LsiScsiControllerStop,
- 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
- NULL, // ImageHandle, to be overwritten by
- // EfiLibInstallDriverBindingComponentName2() in LsiScsiEntryPoint()
- NULL // DriverBindingHandle, ditto
- };
- //
- // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
- // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
- // in English, for display on standard console devices. This is recommended for
- // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
- // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
- //
- // Device type names ("LSI 53C895A SCSI Controller") are not formatted because
- // the driver supports only that device type. Therefore the driver name
- // suffices for unambiguous identification.
- //
- STATIC
- EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
- { "eng;en", L"LSI 53C895A SCSI Controller Driver" },
- { NULL, NULL }
- };
- STATIC
- EFI_COMPONENT_NAME_PROTOCOL gComponentName;
- EFI_STATUS
- EFIAPI
- LsiScsiGetDriverName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN CHAR8 *Language,
- OUT CHAR16 **DriverName
- )
- {
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- mDriverNameTable,
- DriverName,
- (BOOLEAN)(This == &gComponentName) // Iso639Language
- );
- }
- EFI_STATUS
- EFIAPI
- LsiScsiGetDeviceName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN EFI_HANDLE DeviceHandle,
- IN EFI_HANDLE ChildHandle,
- IN CHAR8 *Language,
- OUT CHAR16 **ControllerName
- )
- {
- return EFI_UNSUPPORTED;
- }
- STATIC
- EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
- &LsiScsiGetDriverName,
- &LsiScsiGetDeviceName,
- "eng" // SupportedLanguages, ISO 639-2 language codes
- };
- STATIC
- EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
- (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&LsiScsiGetDriverName,
- (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&LsiScsiGetDeviceName,
- "en" // SupportedLanguages, RFC 4646 language codes
- };
- //
- // Entry point of this driver
- //
- EFI_STATUS
- EFIAPI
- LsiScsiEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- return EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &gDriverBinding,
- ImageHandle, // The handle to install onto
- &gComponentName,
- &gComponentName2
- );
- }
|