From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.120]) by mx.groups.io with SMTP id smtpd.web12.1358.1595016685101250168 for ; Fri, 17 Jul 2020 13:11:25 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=JFW1e/aA; spf=pass (domain: redhat.com, ip: 207.211.31.120, mailfrom: lersek@redhat.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1595016684; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Tg52LTdlVWYBiGQyYgVxhqK/0GQTS5+3tca4dppn1tA=; b=JFW1e/aAud33vtmSD06N1DcNx/YlhAqjB1qrY+20pKRPG1bEpQ2qLV9Kfe5L52cU53eq1H V5p68cv+dug3FlLMBW9Zt2SU0p7S4d3UJJVs0oUo1MZYTxZfBQoXQSxV5QW2SLb+pEl8TY FU20XqPrEQONpQuzVql0/m/K/HwP4Eg= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-339-f__hL4-jOCyrEJ83UBXFPw-1; Fri, 17 Jul 2020 16:11:20 -0400 X-MC-Unique: f__hL4-jOCyrEJ83UBXFPw-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 5E2218015F3; Fri, 17 Jul 2020 20:11:19 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-112-68.ams2.redhat.com [10.36.112.68]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3ABDA6FED1; Fri, 17 Jul 2020 20:11:16 +0000 (UTC) Subject: Re: [PATCH v3 10/11] OvmfPkg/LsiScsiDxe: Process the SCSI Request Packet To: Gary Lin , devel@edk2.groups.io Cc: Jordan Justen , Ard Biesheuvel References: <20200717061130.8881-1-glin@suse.com> <20200717061130.8881-11-glin@suse.com> From: "Laszlo Ersek" Message-ID: Date: Fri, 17 Jul 2020 22:11:15 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 Thunderbird/52.9.1 MIME-Version: 1.0 In-Reply-To: <20200717061130.8881-11-glin@suse.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit On 07/17/20 08:11, Gary Lin wrote: > This is the second part of LsiScsiPassThru(). LsiScsiProcessRequest() is > added to translate the SCSI Request Packet into the LSI 53C895A > commands. This function utilizes the so-called Script buffer to transmit > a series of commands to the chip and then polls the DMA Status (DSTAT) > register until the Scripts Interrupt Instruction Received (SIR) bit > sets. Once the script is done, the SCSI Request Packet will be modified > to reflect the result of the script. The Cumulative SCSI Byte Count > (CSBC) register is fetched before and after the script to calculate the > transferred bytes and update InTransferLength/OutTransferLength if > necessary. > > v3: > - Set DStat, SIst0, and SIst1 to 0 before using them > - Amend the if statements for the DMA data instruction and add the > assertions for the data direction > - Also set SenseDataLength to 0 on the error path > - Fix typos and amend comments > - Amend the error handling of the calculation of transferred bytes > v2: > - Use the BITx macros for the most of LSI_* constants > - Fix a typo: contorller => controller > - Add SeaBIOS lsi-scsi driver as one of the references of the script > - Cast the result of sizeof to UINT32 for the instructions of the > script > - Drop the backslashes > - Replace LSI_SCSI_DMA_ADDR_LOW with LSI_SCSI_DMA_ADDR since we > already removed DUAL_ADDRESS_CYCLE > - Add more comments for the script > - Fix the check of the script size at the end of the script > - Always set SenseDataLength to 0 to avoid the caller to access > SenseData > - Improve the error handling in LsiScsiProcessRequest() > > Cc: Jordan Justen > Cc: Laszlo Ersek > Cc: Ard Biesheuvel > Signed-off-by: Gary Lin > --- > OvmfPkg/Include/IndustryStandard/LsiScsi.h | 64 ++++ > OvmfPkg/LsiScsiDxe/LsiScsi.c | 408 ++++++++++++++++++++- > OvmfPkg/LsiScsiDxe/LsiScsi.h | 21 ++ > OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf | 3 + > OvmfPkg/OvmfPkg.dec | 3 + > 5 files changed, 498 insertions(+), 1 deletion(-) Reviewed-by: Laszlo Ersek Thanks Laszlo > diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h > index 185e553c8eb4..01d75323cdbc 100644 > --- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h > +++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h > @@ -25,6 +25,19 @@ > #define LSI_REG_DSP 0x2C > #define LSI_REG_SIST0 0x42 > #define LSI_REG_SIST1 0x43 > +#define LSI_REG_CSBC 0xDC > + > +// > +// The status bits for DMA Status (DSTAT) > +// > +#define LSI_DSTAT_IID BIT0 > +#define LSI_DSTAT_R BIT1 > +#define LSI_DSTAT_SIR BIT2 > +#define LSI_DSTAT_SSI BIT3 > +#define LSI_DSTAT_ABRT BIT4 > +#define LSI_DSTAT_BF BIT5 > +#define LSI_DSTAT_MDPE BIT6 > +#define LSI_DSTAT_DFE BIT7 > > // > // The status bits for Interrupt Status Zero (ISTAT0) > @@ -38,4 +51,55 @@ > #define LSI_ISTAT0_SRST BIT6 > #define LSI_ISTAT0_ABRT BIT7 > > +// > +// The status bits for SCSI Interrupt Status Zero (SIST0) > +// > +#define LSI_SIST0_PAR BIT0 > +#define LSI_SIST0_RST BIT1 > +#define LSI_SIST0_UDC BIT2 > +#define LSI_SIST0_SGE BIT3 > +#define LSI_SIST0_RSL BIT4 > +#define LSI_SIST0_SEL BIT5 > +#define LSI_SIST0_CMP BIT6 > +#define LSI_SIST0_MA BIT7 > + > +// > +// The status bits for SCSI Interrupt Status One (SIST1) > +// > +#define LSI_SIST1_HTH BIT0 > +#define LSI_SIST1_GEN BIT1 > +#define LSI_SIST1_STO BIT2 > +#define LSI_SIST1_R3 BIT3 > +#define LSI_SIST1_SBMC BIT4 > +#define LSI_SIST1_R5 BIT5 > +#define LSI_SIST1_R6 BIT6 > +#define LSI_SIST1_R7 BIT7 > + > +// > +// LSI 53C895A Script Instructions > +// > +#define LSI_INS_TYPE_BLK 0x00000000 > +#define LSI_INS_TYPE_IO BIT30 > +#define LSI_INS_TYPE_TC BIT31 > + > +#define LSI_INS_BLK_SCSIP_DAT_OUT 0x00000000 > +#define LSI_INS_BLK_SCSIP_DAT_IN BIT24 > +#define LSI_INS_BLK_SCSIP_CMD BIT25 > +#define LSI_INS_BLK_SCSIP_STAT (BIT24 | BIT25) > +#define LSI_INS_BLK_SCSIP_MSG_OUT (BIT25 | BIT26) > +#define LSI_INS_BLK_SCSIP_MSG_IN (BIT24 | BIT25 | BIT26) > + > +#define LSI_INS_IO_OPC_SEL 0x00000000 > +#define LSI_INS_IO_OPC_WAIT_RESEL BIT28 > + > +#define LSI_INS_TC_CP BIT17 > +#define LSI_INS_TC_JMP BIT19 > +#define LSI_INS_TC_RA BIT23 > + > +#define LSI_INS_TC_OPC_JMP 0x00000000 > +#define LSI_INS_TC_OPC_INT (BIT27 | BIT28) > + > +#define LSI_INS_TC_SCSIP_DAT_OUT 0x00000000 > +#define LSI_INS_TC_SCSIP_MSG_IN (BIT24 | BIT25 | BIT26) > + > #endif // _LSI_SCSI_H_ > diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c > index 9859632e02d6..ed5fc3bfdd9d 100644 > --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c > +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c > @@ -43,6 +43,60 @@ Out8 ( > ); > } > > +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 ( > @@ -141,6 +195,357 @@ LsiScsiCheckRequest ( > 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, > @@ -168,7 +573,7 @@ LsiScsiPassThru ( > return Status; > } > > - return EFI_UNSUPPORTED; > + return LsiScsiProcessRequest (Dev, *Target, Lun, Packet); > } > > EFI_STATUS > @@ -474,6 +879,7 @@ LsiScsiControllerStart ( > ); > Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit); > Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit); > + Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec); > > Status = gBS->OpenProtocol ( > ControllerHandle, > diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h > index 05deeed379fe..6ecf523f5a9e 100644 > --- a/OvmfPkg/LsiScsiDxe/LsiScsi.h > +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h > @@ -13,6 +13,11 @@ > #define _LSI_SCSI_DXE_H_ > > typedef struct { > + // > + // Allocate 32 UINT32 entries for the script and it's sufficient for > + // 16 instructions. > + // > + UINT32 Script[32]; > // > // The max size of CDB is 32. > // > @@ -25,6 +30,18 @@ typedef struct { > // Count (DBC), a 24-bit register, so the maximum is 0xFFFFFF (16MB-1). > // > UINT8 Data[SIZE_64KB]; > + // > + // For SCSI Message In phase > + // > + UINT8 MsgIn[2]; > + // > + // For SCSI Message Out phase > + // > + UINT8 MsgOut; > + // > + // For SCSI Status phase > + // > + UINT8 Status; > } LSI_SCSI_DMA_BUFFER; > > typedef struct { > @@ -34,6 +51,7 @@ typedef struct { > EFI_PCI_IO_PROTOCOL *PciIo; > UINT8 MaxTarget; > UINT8 MaxLun; > + UINT32 StallPerPollUsec; > LSI_SCSI_DMA_BUFFER *Dma; > EFI_PHYSICAL_ADDRESS DmaPhysical; > VOID *DmaMapping; > @@ -46,6 +64,9 @@ typedef struct { > #define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \ > CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE) > > +#define LSI_SCSI_DMA_ADDR(Dev, MemberName) \ > + ((UINT32)(Dev->DmaPhysical + OFFSET_OF (LSI_SCSI_DMA_BUFFER, MemberName))) > + > > // > // Probe, start and stop functions of this driver, called by the DXE core for > diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf > index 6111449577a8..4c7abcec618f 100644 > --- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf > +++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf > @@ -41,3 +41,6 @@ [Protocols] > [FixedPcd] > gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit ## CONSUMES > gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit ## CONSUMES > + > +[Pcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec ## CONSUMES > diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec > index ca13a3cb11d3..f16c00ad5b99 100644 > --- a/OvmfPkg/OvmfPkg.dec > +++ b/OvmfPkg/OvmfPkg.dec > @@ -179,6 +179,9 @@ [PcdsFixedAtBuild] > gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit|7|UINT8|0x3b > gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit|0|UINT8|0x3c > > + ## Microseconds to stall between polling for LsiScsi request result > + gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec|5|UINT32|0x3d > + > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8 > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9 > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa >