From nobody Sat Nov 2 16:21:04 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1487887460447840.1489135507717; Thu, 23 Feb 2017 14:04:20 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 35C1C82192; Thu, 23 Feb 2017 14:04:18 -0800 (PST) Received: from foss.arm.com (foss.arm.com [217.140.101.70]) by ml01.01.org (Postfix) with ESMTP id DBAA682184 for ; Thu, 23 Feb 2017 14:04:16 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C771CC28; Thu, 23 Feb 2017 14:04:16 -0800 (PST) Received: from u200856.usa.arm.com (u201426.usa.arm.com [10.118.28.62]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 613C63F483; Thu, 23 Feb 2017 14:04:16 -0800 (PST) X-Original-To: edk2-devel@lists.01.org From: Jeremy Linton To: edk2-devel@lists.01.org Date: Thu, 23 Feb 2017 16:04:00 -0600 Message-Id: <20170223220405.1954-4-jeremy.linton@arm.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170223220405.1954-1-jeremy.linton@arm.com> References: <20170223220405.1954-1-jeremy.linton@arm.com> Subject: [edk2] [PATCH v2 3/7] EmbeddedPkg: SiI3132: Add ScsiProtocol callbacks X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: ard.biesheuvel@linaro.org, Steve.Capper@arm.com, ryan.harkin@linaro.org, leif.lindholm@linaro.org, linaro-uefi@lists.linaro.org MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Create a new module that adds the callbacks to support the EFI SCSI pass-through protocol. These callbacks wrap around the existing ATA pass-through callbacks. In particular the SCSI command submission routine takes the SCSI command and wraps it with an SATA FIS and sets the protocol to ATAPI. It then forwards the FIS to a new routine we will break out of the ATA pass-through callback that manages the FIS submission to the adapter. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeremy Linton --- .../Drivers/SataSiI3132Dxe/SiI3132ScsiPassThru.c | 431 +++++++++++++++++= ++++ 1 file changed, 431 insertions(+) create mode 100644 EmbeddedPkg/Drivers/SataSiI3132Dxe/SiI3132ScsiPassThru.c diff --git a/EmbeddedPkg/Drivers/SataSiI3132Dxe/SiI3132ScsiPassThru.c b/Emb= eddedPkg/Drivers/SataSiI3132Dxe/SiI3132ScsiPassThru.c new file mode 100644 index 0000000..5592947 --- /dev/null +++ b/EmbeddedPkg/Drivers/SataSiI3132Dxe/SiI3132ScsiPassThru.c @@ -0,0 +1,431 @@ +/** @file +* ATAPI support for the Silicon Image I3132 +* +* Copyright (c) 2016, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + + +#include "SataSiI3132.h" + +#include +#include +#include + +EFI_STATUS +SiI3132IDiscoverAtapi ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN INT32 Port + ) +{ + SATA_SI3132_INSTANCE *SataInstance; + SATA_SI3132_PORT *SataPort; + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; + ATA_IDENTIFY_DATA *Data; + EFI_STATUS Status; + EFI_ATA_STATUS_BLOCK *Asb; + EFI_ATA_COMMAND_BLOCK *Acb; + + *SataInstance =3D INSTANCE_FROM_SCSIPASSTHRU_THIS (This); + *SataPort =3D &SataInstance->Ports[Port]; + + Asb=3DAllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BL= OCK)), EFI_PAGE_SIZE); + Acb=3DAllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_COMMAND_B= LOCK)), EFI_PAGE_SIZE); + Data=3DAllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (ATA_IDENTIFY_DAT= A)), EFI_PAGE_SIZE); + ZeroMem (Acb, sizeof (EFI_ATA_COMMAND_BLOCK)); + Acb->AtaCommand =3D ATA_CMD_IDENTIFY_DEVICE; + Acb->AtaDeviceHead =3D (UINT8) (BIT7 | BIT6 | BIT5 ); + + ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET)); + Packet.Acb=3DAcb; + Packet.Asb=3DAsb; + Packet.InDataBuffer =3D Data; + Packet.InTransferLength =3D sizeof (ATA_IDENTIFY_DATA); + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN; + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_L= ENGTH_SECTOR_COUNT; + + Status =3D SiI3132AtaPassThruCommand (SataInstance, SataPort, 0, &Packet= , NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "SiI ATAPI IDENTIFY DEVICE FAILURE %d\n", Status)); + } + else + { + Data->ModelName[39]=3D0; + } + + FreeAlignedPages (Data, EFI_SIZE_TO_PAGES (sizeof (ATA_IDENTIFY_DATA))); + FreeAlignedPages (Acb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_COMMAND_BLOCK)= )); + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK))= ); + + return Status; +} + +EFI_STATUS +SiI3132ScsiPassRead ( + IN SATA_SI3132_INSTANCE *SataInstance, + IN SATA_SI3132_PORT *SataPort, + IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + VOID* PciAllocMapping; + EFI_PHYSICAL_ADDRESS PhysBuffer; + UINTN InDataBufferLength; + VOID *AtaSense; + BOOLEAN RequestSense; + + Status =3D EFI_SUCCESS; + PciIo =3D SataInstance->PciIo; + PciAllocMapping =3D NULL; + InDataBufferLength =3D Packet->InTransferLength; + AtaSense =3D AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_ST= ATUS_BLOCK)), + EFI_PAGE_SIZE);; + RequestSense =3D FALSE; + + DEBUG ((DEBUG_VERBOSE, "SiI3132ScsiPassRead() CDB[0]:%X len=3D%d\n", + ((UINT8*)Packet->Cdb)[0], Packet->InTransferLength)); + + if (AtaSense) { + if (Packet->InTransferLength) { + Status =3D PciIo->Map (SataInstance->PciIo, EfiPciIoOperationBusMast= erRead, + Packet->InDataBuffer, &InDataBufferLength, + &PhysBuffer, &PciAllocMapping); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SiI map() failure %d\n", Status)); + return Status; + } + } else { + PhysBuffer=3D0; + } + do { + // SI "The host driver must populate the area normaly used for the f= irst SGE + // with the desired ATAPI command". AKA, put the SCSI CDB itself (no= t the address) + // in the 12 bytes comprising the SGE[0]. + ZeroMem (&SataPort->HostPRB->Sge[0], sizeof (SATA_SI3132_SGE)); + CopyMem (&SataPort->HostPRB->Sge[0], (UINT8*)Packet->Cdb, Packet->Cd= bLength); + + // The SGE for the data buffer + SataPort->HostPRB->Sge[1].DataAddressLow =3D (UINT64)PhysBuffer; + SataPort->HostPRB->Sge[1].DataAddressHigh =3D ((UINT64)(PhysBuffer) = >> 32); + SataPort->HostPRB->Sge[1].Attributes =3D SGE_TRM; + SataPort->HostPRB->Sge[1].DataCount =3D Packet->InTransferLength; + + // Create the ATA FIS + SataPort->HostPRB->Control =3D (Packet->InTransferLength ? PRB_CTRL_= PKT_READ:0); + SataPort->HostPRB->ProtocolOverride =3D 0; + + // This is an ATA PACKET command, which encapuslates the ATAPI(sorta= SCSI) command + SataPort->HostPRB->Fis.FisType =3D SII_FIS_REGISTER_H2D; // Registe= r - Host to Device FIS + SataPort->HostPRB->Fis.Control =3D SII_FIS_CONTROL_CMD; // Is a co= mmand + SataPort->HostPRB->Fis.Command =3D ATA_CMD_PACKET; + SataPort->HostPRB->Fis.Features =3D 1; + SataPort->HostPRB->Fis.Fis[0] =3D 0; + SataPort->HostPRB->Fis.Fis[1] =3D (UINT8) (((UINT64)PhysBuffer) & = 0x00ff); + SataPort->HostPRB->Fis.Fis[2] =3D (UINT8) (((UINT64)PhysBuffer) >>= 8); + SataPort->HostPRB->Fis.Fis[3] =3D 0x40; + + // Issue this as an ATA command + Status =3D SiI3132IssueCommand (SataPort, PciIo, Packet->Timeout, At= aSense); + + if (RequestSense) { + // If we were trying to send a request sense in response to a fail= ure + // Check conditions are a normal part of SCSI operation, its expec= ted + // that most devices will do a 6/2900 (reset) and 2/2800 (media ch= ange) + // at startup. + UINT8 *sense; + + sense =3D (UINT8 *)Packet->SenseData; + RequestSense=3DFALSE; + Packet->InTransferLength =3D 0; + Packet->HostAdapterStatus =3D EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK; + Packet->TargetStatus =3D EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITIO= N; + if ((Packet->SenseDataLength > 13) && + (sense[0] & EFI_SCSI_REQUEST_SENSE_ERROR)) { + DEBUG ((DEBUG_INFO, "SiI3132ScsiPassRead() Key %X ASC(Q) %02X%02= X\n", + EFI_SCSI_SK_VALUE (sense[2]), sense[12], sense[13])); + } + Status =3D EFI_SUCCESS; + } else if (!EFI_ERROR (Status)) { + Packet->HostAdapterStatus =3D EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK; + Packet->TargetStatus =3D EFI_EXT_SCSI_STATUS_TARGET_GOOD; + ZeroMem (Packet->SenseData, Packet->SenseDataLength); + Packet->SenseDataLength =3D 0; + } else if (Status =3D=3D EFI_TIMEOUT) { + SiI3132HwResetPort (SataPort); + Packet->HostAdapterStatus =3D EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTH= ER; + Packet->SenseDataLength =3D 0; + Packet->InTransferLength =3D 0; + } else { + // Assume for now, that if we didn't succeed that it was a check c= ondition. + // ATAPI can't autosense on SiI, so lets emulate it with an explic= it + // request sense into the sense buffer. + Packet->HostAdapterStatus =3D EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTH= ER; + if ((RequestSense =3D=3D FALSE) && (Packet->SenseDataLength)) { + if (Packet->SenseDataLength >=3D SI_MAX_SENSE) { + Packet->SenseDataLength =3D SI_MAX_SENSE - 1; + } + Packet->CdbLength =3D 6; //Request Sense is a 6 byte CDB + ZeroMem (Packet->Cdb, SI_MAX_CDB); + ((char*)Packet->Cdb)[0] =3D EFI_SCSI_OP_REQUEST_SENSE; + ((char*)Packet->Cdb)[4] =3D Packet->SenseDataLength; + + ZeroMem (SataPort->HostPRB, sizeof (SATA_SI3132_PRB)); + if (PciAllocMapping) { + PciIo->Unmap (PciIo, PciAllocMapping); + } + + Packet->InTransferLength =3D Packet->SenseDataLength; + InDataBufferLength =3D Packet->SenseDataLength; + Status =3D PciIo->Map (SataInstance->PciIo, EfiPciIoOperationBus= MasterRead, + Packet->SenseData, &InDataBufferLength, &Ph= ysBuffer, &PciAllocMapping); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SiI map() sense failure %d\n", Status)); + Packet->SenseDataLength =3D 0; + } else { + // Everything seems ok, lets issue a SCSI sense + RequestSense =3D TRUE; + } + } + } + } while (RequestSense); + + if (PciAllocMapping) { + PciIo->Unmap (PciIo, PciAllocMapping); + } + } else { + DEBUG ((DEBUG_ERROR, "SCSI PassThru Unable to allocate sense buffer\n"= )); + Status =3D EFI_OUT_OF_RESOURCES; + } + return Status; +} + +EFI_STATUS +SiI3132ScsiPassThru ( + 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; + SATA_SI3132_INSTANCE *SataInstance; + SATA_SI3132_PORT *SataPort; + + Status =3D EFI_SUCCESS; + SataInstance =3D INSTANCE_FROM_SCSIPASSTHRU_THIS (This); + SataPort =3D &SataInstance->Ports[Target[0]]; + ZeroMem (SataPort->HostPRB, sizeof (SATA_SI3132_PRB)); + + switch (Packet->DataDirection) { + case EFI_EXT_SCSI_DATA_DIRECTION_READ: + Status =3D SiI3132ScsiPassRead (SataInstance,SataPort, Packet); + break; + case EFI_EXT_SCSI_DATA_DIRECTION_WRITE: + // TODO, fill this in if we ever want to connect something + // besides a simple CDROM/DVDROM + default: + DEBUG ((DEBUG_ERROR, "SCSI PassThru Unsupported direction\n")); + } + + return Status; +} + +UINT8 mScsiId[TARGET_MAX_BYTES] =3D { + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF +}; + +// With ATA, there are potentially three levels of addressing: port, portm= ultiplier, lun +// although I'm not sure there are any actual multilun devices anymore (cd= autoloaders/etc) +// on ATA the common disk/cdroms generally are single lun devices. So, let= s skip the LUN +// scanning/addressing. Futher, the standard ATAPI spec doesn't support lu= n's. +EFI_STATUS +SiI3132GetNextTargetLun ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN OUT UINT8 **Target, + IN OUT UINT64 *Lun + ) +{ + EFI_STATUS Status; + SATA_SI3132_INSTANCE *SataInstance; + UINT8 *Target8; + + Status =3D EFI_NOT_FOUND; + SataInstance =3D INSTANCE_FROM_SCSIPASSTHRU_THIS (This); + DEBUG ((DEBUG_INFO, "SCSI GetNextTargetLun L:%d\n",*Lun)); + if (!SataInstance) { + DEBUG ((DEBUG_ERROR, "SCSI GetNextTargetLun no instance\n",Lun)); + return EFI_INVALID_PARAMETER; + } + + if (Target =3D=3D NULL || Lun =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + if (*Target =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*Lun > 0) { + DEBUG ((DEBUG_ERROR, "SCSI GetNextTargetLun Only supports lun0 at the = moment\n",Lun)); + return EFI_INVALID_PARAMETER; + } + + Target8 =3D *Target; + + // look for first device + if (CompareMem (Target8, mScsiId, TARGET_MAX_BYTES) =3D=3D 0) { + BOOLEAN Found; + INT32 Index; + + Found =3D FALSE; + Target8 =3D *Target; + for (Index =3D 0; ((Index < SATA_SII3132_MAXPORT) && (!Found)); Index+= +) { + SATA_SI3132_PORT *SataPort; + LIST_ENTRY *List; + INT32 Multiplier; + + SataPort =3D &(SataInstance->Ports[Index]); + List =3D SataPort->Devices.ForwardLink; + Multiplier =3D 0; + while ((List !=3D &SataPort->Devices) && (!Found)) { + SATA_SI3132_DEVICE* SataDevice; + + SataDevice =3D (SATA_SI3132_DEVICE*)List; + if (SataDevice->Atapi) { + Found =3D TRUE; + Target8[0] =3D Index; + Target8[1] =3D Multiplier; //the device on this port (for port m= ultipliers) + DEBUG ((DEBUG_INFO, "SCSI GetNextTargetLun found device at %d %d= \n",Index,Multiplier)); + SiI3132IDiscoverAtapi (This, Index); + + Status =3D EFI_SUCCESS; + break; + } + List =3D List->ForwardLink; + Multiplier++; + } + } + } else { + //todo find the next device, + } + + return Status; +} + +EFI_STATUS +SiI3132GetNextTargetLun2 ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT8 *Target, + IN UINT64 Lun, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + EFI_STATUS Status; + + Status =3D EFI_SUCCESS; + DEBUG ((DEBUG_INFO, "SCSI GetNextTargetLun2\n")); + return Status; +} + +EFI_STATUS +SiI3132ScsiBuildDevicePath ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT8 *Target, + IN UINT64 Lun, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + SATA_SI3132_INSTANCE *SataInstance; + + SataInstance =3D INSTANCE_FROM_SCSIPASSTHRU_THIS (This); + DEBUG ((DEBUG_INFO, "SCSI BuildDevicePath T:%d L:%d\n",*Target,Lun)); + + if (Lun<1) { + return SiI3132BuildDevicePath (&SataInstance->AtaPassThruProtocol, Tar= get[0], Target[1], DevicePath); + } + return EFI_NOT_FOUND; +} + +EFI_STATUS +SiI3132GetTargetLun ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT8 **Target, + OUT UINT64 *Lun + ) +{ + EFI_STATUS Status; + + Status =3D EFI_SUCCESS; + DEBUG ((DEBUG_INFO, "SCSI GetNextTarget T:%d L:%d\n",*Target,Lun)); + return Status; +} + +// So normally we would want to do a ATA port reset here (which is general= ly +// frowned on with modern SCSI transports (sas, fc, etc) unless all the +// attached devices are in an error state). But the EFI SCSI protocol isn't +// specific enough to specify a device for which we want to reset the port. +// This means we are basically stuck simulating it by resetting all the po= rts +// which is bad karma. So lets just claim its unsupported and if we discov= er +// that port resets are needed as part of the target/lun reset then consid= er +// doing it automatically as part of that path. +EFI_STATUS +SiI3132ResetChannel ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This + ) +{ + EFI_STATUS Status; + Status =3D EFI_UNSUPPORTED; + + DEBUG ((DEBUG_ERROR, "SCSI ResetChannel\n")); + return Status; +} + +// Just do a device reset here, in the future if we find out that is insuf= ficient +// try to just reset the SATA port the device is attached to as well. +EFI_STATUS +SiI3132ResetTargetLun ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT8 *Target, + IN UINT64 Lun + ) +{ + EFI_STATUS Status; + SATA_SI3132_INSTANCE *SataInstance; + + Status =3D EFI_NOT_FOUND; + SataInstance =3D INSTANCE_FROM_SCSIPASSTHRU_THIS (This); + + DEBUG ((DEBUG_ERROR, "SCSI ResetTargetLun\n")); + + if (Lun<1) { + Status =3D SiI3132ResetDevice (&SataInstance->AtaPassThruProtocol, + Target[0], Target[1]); + } + return Status; +} + +EFI_STATUS +SiI3132GetNextTarget ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN OUT UINT8 **Target + ) +{ + EFI_STATUS Status; + + Status =3D EFI_SUCCESS; + DEBUG ((DEBUG_VERBOSE, "SCSI GetNextTarget\n")); + return Status; +} --=20 2.9.3 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel