X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FBus%2FAta%2FAtaAtapiPassThru%2FAtaAtapiPassThru.c;h=09064dda18b70753d6a100ad21e9855c90291e78;hp=35477d886257285b4ea8d796eaa95dde05bc35d6;hb=0641808ece210dd2855a69302a0876af7bdc44a2;hpb=df202d72ebce0178d93eca8281ede0362cc1f36c diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c index 35477d8862..09064dda18 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c @@ -2,7 +2,7 @@ This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces for managed ATA controllers. - Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -94,6 +94,7 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = { NULL, NULL }, + 0, // EnabledPciAttributes 0, // OriginalAttributes 0, // PreviousPort 0, // PreviousPortMultiplier @@ -103,7 +104,8 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = { { // NonBlocking TaskList NULL, NULL - } + }, + NULL, // ExitBootEvent }; ATAPI_DEVICE_PATH mAtapiDevicePathTemplate = { @@ -148,7 +150,7 @@ UINT8 mScsiId[TARGET_MAX_BYTES] = { @param[in] Port The port number of the ATA device to send the command. @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command. - If there is no port multiplier, then specify 0. + If there is no port multiplier, then specify 0xFFFF. @param[in, out] Packet A pointer to the ATA command to send to the ATA device specified by Port and PortMultiplierPort. @param[in] Instance Pointer to the ATA_ATAPI_PASS_THRU_INSTANCE. @@ -272,6 +274,14 @@ AtaPassThruPassThruExecute ( } break; case EfiAtaAhciMode : + if (PortMultiplierPort == 0xFFFF) { + // + // If there is no port multiplier, PortMultiplierPort will be 0xFFFF + // according to UEFI spec. Here, we convert its value to 0 to follow + // AHCI spec. + // + PortMultiplierPort = 0; + } switch (Protocol) { case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA: Status = AhciNonDataTransfer ( @@ -469,6 +479,38 @@ InitializeAtaAtapiPassThru ( return Status; } +/** + Disable the device (especially Bus Master DMA) when exiting the boot + services. + + @param[in] Event Event for which this notification function is being + called. + @param[in] Context Pointer to the ATA_ATAPI_PASS_THRU_INSTANCE that + represents the HBA. +**/ +VOID +EFIAPI +AtaPassThruExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + ATA_ATAPI_PASS_THRU_INSTANCE *Instance; + EFI_PCI_IO_PROTOCOL *PciIo; + + DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context)); + + Instance = Context; + PciIo = Instance->PciIo; + + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, + Instance->EnabledPciAttributes, + NULL + ); +} + /** Tests to see if this driver supports a given controller. If a child device is provided, it further tests to see if this driver supports creating a handle for the specified child device. @@ -662,7 +704,7 @@ AtaAtapiPassThruStart ( EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInit; ATA_ATAPI_PASS_THRU_INSTANCE *Instance; EFI_PCI_IO_PROTOCOL *PciIo; - UINT64 Supports; + UINT64 EnabledPciAttributes; UINT64 OriginalPciAttributes; Status = EFI_SUCCESS; @@ -714,14 +756,14 @@ AtaAtapiPassThruStart ( PciIo, EfiPciIoAttributeOperationSupported, 0, - &Supports + &EnabledPciAttributes ); if (!EFI_ERROR (Status)) { - Supports &= EFI_PCI_DEVICE_ENABLE; + EnabledPciAttributes &= (UINT64)EFI_PCI_DEVICE_ENABLE; Status = PciIo->Attributes ( PciIo, EfiPciIoAttributeOperationEnable, - Supports, + EnabledPciAttributes, NULL ); } @@ -741,12 +783,24 @@ AtaAtapiPassThruStart ( Instance->ControllerHandle = Controller; Instance->IdeControllerInit = IdeControllerInit; Instance->PciIo = PciIo; + Instance->EnabledPciAttributes = EnabledPciAttributes; Instance->OriginalPciAttributes = OriginalPciAttributes; Instance->AtaPassThru.Mode = &Instance->AtaPassThruMode; Instance->ExtScsiPassThru.Mode = &Instance->ExtScsiPassThruMode; InitializeListHead(&Instance->DeviceList); InitializeListHead(&Instance->NonBlockingTaskList); + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_CALLBACK, + AtaPassThruExitBootServices, + Instance, + &Instance->ExitBootEvent + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + Instance->TimerEvent = NULL; Status = gBS->CreateEvent ( @@ -800,6 +854,10 @@ ErrorExit: gBS->CloseEvent (Instance->TimerEvent); } + if ((Instance != NULL) && (Instance->ExitBootEvent != NULL)) { + gBS->CloseEvent (Instance->ExitBootEvent); + } + // // Remove all inserted ATA devices. // @@ -851,7 +909,6 @@ AtaAtapiPassThruStop ( EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; EFI_PCI_IO_PROTOCOL *PciIo; EFI_AHCI_REGISTERS *AhciRegisters; - UINT64 Supports; DEBUG ((EFI_D_INFO, "==AtaAtapiPassThru Stop== Controller = %x\n", Controller)); @@ -870,6 +927,27 @@ AtaAtapiPassThruStop ( Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (AtaPassThru); + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiAtaPassThruProtocolGuid, &(Instance->AtaPassThru), + &gEfiExtScsiPassThruProtocolGuid, &(Instance->ExtScsiPassThru), + NULL + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Close protocols opened by AtaAtapiPassThru controller driver + // + gBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + // // Close Non-Blocking timer and free Task list. // @@ -880,57 +958,29 @@ AtaAtapiPassThruStop ( DestroyAsynTaskList (Instance, FALSE); // - // Disable this ATA host controller. + // Close event signaled at gBS->ExitBootServices(). // - PciIo = Instance->PciIo; - Status = PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationSupported, - 0, - &Supports - ); - if (!EFI_ERROR (Status)) { - Supports &= EFI_PCI_DEVICE_ENABLE; - PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationDisable, - Supports, - NULL - ); + if (Instance->ExitBootEvent != NULL) { + gBS->CloseEvent (Instance->ExitBootEvent); + Instance->ExitBootEvent = NULL; } // - // Restore original PCI attributes + // Free allocated resource // - Status = PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationSet, - Instance->OriginalPciAttributes, - NULL - ); - ASSERT_EFI_ERROR (Status); + DestroyDeviceInfoList (Instance); - gBS->UninstallMultipleProtocolInterfaces ( - Controller, - &gEfiAtaPassThruProtocolGuid, &(Instance->AtaPassThru), - &gEfiExtScsiPassThruProtocolGuid, &(Instance->ExtScsiPassThru), - NULL - ); - - // - // Close protocols opened by AtaAtapiPassThru controller driver - // - gBS->CloseProtocol ( - Controller, - &gEfiIdeControllerInitProtocolGuid, - This->DriverBindingHandle, - Controller - ); + PciIo = Instance->PciIo; // - // Free allocated resource + // Disable this ATA host controller. // - DestroyDeviceInfoList(Instance); + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, + Instance->EnabledPciAttributes, + NULL + ); // // If the current working mode is AHCI mode, then pre-allocated resource @@ -966,6 +1016,18 @@ AtaAtapiPassThruStop ( AhciRegisters->AhciRFis ); } + + // + // Restore original PCI attributes + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + Instance->OriginalPciAttributes, + NULL + ); + ASSERT_EFI_ERROR (Status); + FreePool (Instance); return Status; @@ -977,7 +1039,7 @@ AtaAtapiPassThruStop ( @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance. @param[in] Port The port number of the ATA device to send the command. @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command. - If there is no port multiplier, then specify 0. + If there is no port multiplier, then specify 0xFFFF. @param[in] DeviceType The device type of the ATA device. @retval The pointer to the data structure of the device info to access. @@ -999,6 +1061,18 @@ SearchDeviceInfoList ( while (!IsNull (&Instance->DeviceList, Node)) { DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node); + // + // For CD-ROM working in the AHCI mode, only 8 bits are used to record + // the PortMultiplier information. If the CD-ROM is directly attached + // on a SATA port, the PortMultiplier should be translated from 0xFF + // to 0xFFFF according to the UEFI spec. + // + if ((Instance->Mode == EfiAtaAhciMode) && + (DeviceInfo->Type == EfiIdeCdrom) && + (PortMultiplier == 0xFF)) { + PortMultiplier = 0xFFFF; + } + if ((DeviceInfo->Type == DeviceType) && (Port == DeviceInfo->Port) && (PortMultiplier == DeviceInfo->PortMultiplier)) { @@ -1018,7 +1092,7 @@ SearchDeviceInfoList ( @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance. @param[in] Port The port number of the ATA device to send the command. @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command. - If there is no port multiplier, then specify 0. + If there is no port multiplier, then specify 0xFFFF. @param[in] DeviceType The device type of the ATA device. @param[in] IdentifyData The data buffer to store the output of the IDENTIFY cmd. @@ -1211,7 +1285,7 @@ Done: @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance. @param[in] Port The port number of the ATA device to send the command. @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command. - If there is no port multiplier, then specify 0. + If there is no port multiplier, then specify 0xFFFF. @param[in, out] Packet A pointer to the ATA command to send to the ATA device specified by Port and PortMultiplierPort. @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking @@ -1250,6 +1324,7 @@ AtaPassThruPassThru ( UINT32 MaxSectorCount; ATA_NONBLOCK_TASK *Task; EFI_TPL OldTpl; + UINT32 BlockSize; Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This); @@ -1274,22 +1349,6 @@ AtaPassThruPassThru ( } } - // - // convert the transfer length from sector count to byte. - // - if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) && - (Packet->InTransferLength != 0)) { - Packet->InTransferLength = Packet->InTransferLength * 0x200; - } - - // - // convert the transfer length from sector count to byte. - // - if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) && - (Packet->OutTransferLength != 0)) { - Packet->OutTransferLength = Packet->OutTransferLength * 0x200; - } - // // Check whether this device needs 48-bit addressing (ATAPI-6 ata device). // Per ATA-6 spec, word83: bit15 is zero and bit14 is one. @@ -1309,13 +1368,39 @@ AtaPassThruPassThru ( } } + BlockSize = 0x200; + if ((IdentifyData->AtaData.phy_logic_sector_support & (BIT14 | BIT15)) == BIT14) { + // + // Check logical block size + // + if ((IdentifyData->AtaData.phy_logic_sector_support & BIT12) != 0) { + BlockSize = (UINT32) (((IdentifyData->AtaData.logic_sector_size_hi << 16) | IdentifyData->AtaData.logic_sector_size_lo) * sizeof (UINT16)); + } + } + + // + // convert the transfer length from sector count to byte. + // + if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) && + (Packet->InTransferLength != 0)) { + Packet->InTransferLength = Packet->InTransferLength * BlockSize; + } + + // + // convert the transfer length from sector count to byte. + // + if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) && + (Packet->OutTransferLength != 0)) { + Packet->OutTransferLength = Packet->OutTransferLength * BlockSize; + } + // // If the data buffer described by InDataBuffer/OutDataBuffer and InTransferLength/OutTransferLength // is too big to be transferred in a single command, then no data is transferred and EFI_BAD_BUFFER_SIZE // is returned. // - if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * 0x200)) || - ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * 0x200))) { + if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * BlockSize)) || + ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * BlockSize))) { return EFI_BAD_BUFFER_SIZE; } @@ -1334,7 +1419,12 @@ AtaPassThruPassThru ( Task->Packet = Packet; Task->Event = Event; Task->IsStart = FALSE; - Task->RetryTimes = 0; + Task->RetryTimes = DivU64x32(Packet->Timeout, 1000) + 1; + if (Packet->Timeout == 0) { + Task->InfiniteWait = TRUE; + } else { + Task->InfiniteWait = FALSE; + } OldTpl = gBS->RaiseTPL (TPL_NOTIFY); InsertTailList (&Instance->NonBlockingTaskList, &Task->Link); @@ -1510,17 +1600,25 @@ AtaPassThruGetNextDevice ( return EFI_INVALID_PARAMETER; } - if (*PortMultiplierPort == 0xFFFF) { + if (Instance->PreviousPortMultiplier == 0xFFFF) { // - // If the PortMultiplierPort is all 0xFF's, start to traverse the device list from the beginning + // If a device is directly attached on a port, previous call to this + // function will return the value 0xFFFF for PortMultiplierPort. In + // this case, there should be no more device on the port multiplier. // + Instance->PreviousPortMultiplier = 0; + return EFI_NOT_FOUND; + } + + if (*PortMultiplierPort == Instance->PreviousPortMultiplier) { Node = GetFirstNode (&Instance->DeviceList); while (!IsNull (&Instance->DeviceList, Node)) { DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node); if ((DeviceInfo->Type == EfiIdeHarddisk) && - (DeviceInfo->Port == Port)){ + (DeviceInfo->Port == Port) && + (DeviceInfo->PortMultiplier > *PortMultiplierPort)){ *PortMultiplierPort = DeviceInfo->PortMultiplier; goto Exit; } @@ -1529,15 +1627,17 @@ AtaPassThruGetNextDevice ( } return EFI_NOT_FOUND; - } else if (*PortMultiplierPort == Instance->PreviousPortMultiplier) { + } else if (*PortMultiplierPort == 0xFFFF) { + // + // If the PortMultiplierPort is all 0xFF's, start to traverse the device list from the beginning + // Node = GetFirstNode (&Instance->DeviceList); while (!IsNull (&Instance->DeviceList, Node)) { DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node); if ((DeviceInfo->Type == EfiIdeHarddisk) && - (DeviceInfo->Port == Port) && - (DeviceInfo->PortMultiplier > *PortMultiplierPort)){ + (DeviceInfo->Port == Port)){ *PortMultiplierPort = DeviceInfo->PortMultiplier; goto Exit; } @@ -1580,7 +1680,7 @@ Exit: device path node is to be allocated and built. @param[in] PortMultiplierPort The port multiplier port number of the ATA device for which a device path node is to be allocated and built. If there is no - port multiplier, then specify 0. + port multiplier, then specify 0xFFFF. @param[in, out] DevicePath A pointer to a single device path node that describes the ATA device specified by Port and PortMultiplierPort. This function is responsible for allocating the buffer DevicePath with the @@ -1764,7 +1864,10 @@ AtaPassThruResetPort ( IN UINT16 Port ) { - return EFI_UNSUPPORTED; + // + // Return success directly then upper layer driver could think reset port operation is done. + // + return EFI_SUCCESS; } /** @@ -1788,7 +1891,7 @@ AtaPassThruResetPort ( @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance. @param[in] Port Port represents the port number of the ATA device to be reset. @param[in] PortMultiplierPort The port multiplier port number of the ATA device to reset. - If there is no port multiplier, then specify 0. + If there is no port multiplier, then specify 0xFFFF. @retval EFI_SUCCESS The ATA device specified by Port and PortMultiplierPort was reset. @retval EFI_UNSUPPORTED The ATA controller does not support a device reset operation. @retval EFI_INVALID_PARAMETER Port or PortMultiplierPort are invalid. @@ -1806,7 +1909,72 @@ AtaPassThruResetDevice ( IN UINT16 PortMultiplierPort ) { - return EFI_UNSUPPORTED; + ATA_ATAPI_PASS_THRU_INSTANCE *Instance; + LIST_ENTRY *Node; + + Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This); + + Node = SearchDeviceInfoList (Instance, Port, PortMultiplierPort, EfiIdeHarddisk); + + if (Node == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Return success directly then upper layer driver could think reset device operation is done. + // + return EFI_SUCCESS; +} + +/** + Submit ATAPI request sense command. + + @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance. + @param[in] Target The Target is an array of size TARGET_MAX_BYTES and it represents + the id of the SCSI device to send the SCSI Request Packet. Each + transport driver may choose to utilize a subset of this size to suit the needs + of transport target representation. For example, a Fibre Channel driver + may use only 8 bytes (WWN) to represent an FC target. + @param[in] Lun The LUN of the SCSI device to send the SCSI Request Packet. + @param[in] SenseData A pointer to store sense data. + @param[in] SenseDataLength The sense data length. + @param[in] Timeout The timeout value to execute this cmd, uses 100ns as a unit. + + @retval EFI_SUCCESS Send out the ATAPI packet command successfully. + @retval EFI_DEVICE_ERROR The device failed to send data. + +**/ +EFI_STATUS +EFIAPI +AtaPacketRequestSense ( + IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, + IN UINT8 *Target, + IN UINT64 Lun, + IN VOID *SenseData, + IN UINT8 SenseDataLength, + IN UINT64 Timeout + ) +{ + EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet; + UINT8 Cdb[12]; + EFI_STATUS Status; + + ZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 12); + + Cdb[0] = ATA_CMD_REQUEST_SENSE; + Cdb[4] = SenseDataLength; + + Packet.Timeout = Timeout; + Packet.Cdb = Cdb; + Packet.CdbLength = 12; + Packet.DataDirection = EFI_EXT_SCSI_DATA_DIRECTION_READ; + Packet.InDataBuffer = SenseData; + Packet.InTransferLength = SenseDataLength; + + Status = ExtScsiPassThruPassThru (This, Target, Lun, &Packet, NULL); + + return Status; } /** @@ -1867,8 +2035,13 @@ ExtScsiPassThruPassThru ( EFI_ATA_HC_WORK_MODE Mode; LIST_ENTRY *Node; EFI_ATA_DEVICE_INFO *DeviceInfo; + BOOLEAN SenseReq; + EFI_SCSI_SENSE_DATA *PtrSenseData; + UINTN SenseDataLen; + EFI_STATUS SenseStatus; - Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This); + SenseDataLen = 0; + Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This); if ((Packet == NULL) || (Packet->Cdb == NULL)) { return EFI_INVALID_PARAMETER; @@ -1882,6 +2055,10 @@ ExtScsiPassThruPassThru ( return EFI_INVALID_PARAMETER; } + if ((Packet->SenseDataLength != 0) && (Packet->SenseData == NULL)) { + return EFI_INVALID_PARAMETER; + } + if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) { return EFI_INVALID_PARAMETER; } @@ -1929,6 +2106,10 @@ ExtScsiPassThruPassThru ( // if (*((UINT8*)Packet->Cdb) == ATA_CMD_IDENTIFY_DEVICE) { CopyMem (Packet->InDataBuffer, DeviceInfo->IdentifyData, sizeof (EFI_IDENTIFY_DATA)); + // + // For IDENTIFY DEVICE cmd, we don't need to get sense data. + // + Packet->SenseDataLength = 0; return EFI_SUCCESS; } @@ -1947,6 +2128,13 @@ ExtScsiPassThruPassThru ( Status = AtaPacketCommandExecute (Instance->PciIo, &Instance->IdeRegisters[Port], Port, PortMultiplier, Packet); break; case EfiAtaAhciMode: + if (PortMultiplier == 0xFF) { + // + // If there is no port multiplier, the PortMultiplier will be 0xFF + // Here, we convert its value to 0 to follow the AHCI spec. + // + PortMultiplier = 0; + } Status = AhciPacketCommandExecute (Instance->PciIo, &Instance->AhciRegisters, Port, PortMultiplier, Packet); break; default : @@ -1954,6 +2142,46 @@ ExtScsiPassThruPassThru ( break; } + // + // If the cmd doesn't get executed correctly, then check sense data. + // + if (EFI_ERROR (Status) && (Packet->SenseDataLength != 0) && (*((UINT8*)Packet->Cdb) != ATA_CMD_REQUEST_SENSE)) { + PtrSenseData = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA)), This->Mode->IoAlign); + if (PtrSenseData == NULL) { + return EFI_DEVICE_ERROR; + } + + for (SenseReq = TRUE; SenseReq;) { + SenseStatus = AtaPacketRequestSense ( + This, + Target, + Lun, + PtrSenseData, + sizeof (EFI_SCSI_SENSE_DATA), + Packet->Timeout + ); + if (EFI_ERROR (SenseStatus)) { + break; + } + + CopyMem ((UINT8*)Packet->SenseData + SenseDataLen, PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA)); + SenseDataLen += sizeof (EFI_SCSI_SENSE_DATA); + + // + // no more sense key or number of sense keys exceeds predefined, + // skip the loop. + // + if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) || + (SenseDataLen + sizeof (EFI_SCSI_SENSE_DATA) > Packet->SenseDataLength)) { + SenseReq = FALSE; + } + } + FreeAlignedPages (PtrSenseData, EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA))); + } + // + // Update the SenseDataLength field to the data length received. + // + Packet->SenseDataLength = (UINT8)SenseDataLen; return Status; } @@ -2044,7 +2272,7 @@ ExtScsiPassThruGetNextTargetLun ( if ((DeviceInfo->Type == EfiIdeCdrom) && ((Target8[0] < DeviceInfo->Port) || ((Target8[0] == DeviceInfo->Port) && - (Target8[1] < DeviceInfo->PortMultiplier)))) { + (Target8[1] < (UINT8)DeviceInfo->PortMultiplier)))) { Target8[0] = (UINT8)DeviceInfo->Port; Target8[1] = (UINT8)DeviceInfo->PortMultiplier; goto Exit; @@ -2166,7 +2394,13 @@ ExtScsiPassThruBuildDevicePath ( } DevicePathNode->Sata.HBAPortNumber = Port; - DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplier; + // + // For CD-ROM working in the AHCI mode, only 8 bits are used to record + // the PortMultiplier information. If the CD-ROM is directly attached + // on a SATA port, the PortMultiplier should be translated from 0xFF + // to 0xFFFF according to the UEFI spec. + // + DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplier == 0xFF ? 0xFFFF : PortMultiplier; DevicePathNode->Sata.Lun = (UINT16) Lun; } @@ -2274,7 +2508,10 @@ ExtScsiPassThruResetChannel ( IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This ) { - return EFI_UNSUPPORTED; + // + // Return success directly then upper layer driver could think reset channel operation is done. + // + return EFI_SUCCESS; } /** @@ -2304,7 +2541,41 @@ ExtScsiPassThruResetTargetLun ( IN UINT64 Lun ) { - return EFI_UNSUPPORTED; + ATA_ATAPI_PASS_THRU_INSTANCE *Instance; + LIST_ENTRY *Node; + UINT8 Port; + UINT8 PortMultiplier; + + Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This); + // + // For ATAPI device, doesn't support multiple LUN device. + // + if (Lun != 0) { + return EFI_INVALID_PARAMETER; + } + // + // The layout of Target array: + // ________________________________________________________________________ + // | Byte 0 | Byte 1 | ... | TARGET_MAX_BYTES - 1 | + // |_____________________|_____________________|_____|______________________| + // | | The port multiplier | | | + // | The port number | port number | N/A | N/A | + // |_____________________|_____________________|_____|______________________| + // + // For ATAPI device, 2 bytes is enough to represent the location of SCSI device. + // + Port = Target[0]; + PortMultiplier = Target[1]; + + Node = SearchDeviceInfoList(Instance, Port, PortMultiplier, EfiIdeCdrom); + if (Node == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Return success directly then upper layer driver could think reset target LUN operation is done. + // + return EFI_SUCCESS; } /** @@ -2383,7 +2654,7 @@ ExtScsiPassThruGetNextTarget ( if ((DeviceInfo->Type == EfiIdeCdrom) && ((Target8[0] < DeviceInfo->Port) || ((Target8[0] == DeviceInfo->Port) && - (Target8[1] < DeviceInfo->PortMultiplier)))) { + (Target8[1] < (UINT8)DeviceInfo->PortMultiplier)))) { Target8[0] = (UINT8)DeviceInfo->Port; Target8[1] = (UINT8)DeviceInfo->PortMultiplier; goto Exit;