X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FUsb%2FUsbMassStorageDxe%2FUsbMassBoot.c;h=600896b6a2147c6c5cc17356a842b44347000434;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hp=44f0b03833258e96181b4f270065590cffb401e8;hpb=d80ed2a76eec1786412fb76cc080cfb38ae77011;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c index 44f0b03833..600896b6a2 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c @@ -2,25 +2,19 @@ Implementation of the command set of USB Mass Storage Specification for Bootability, Revision 1.0. -Copyright (c) 2007 - 2008, 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 -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 IMPLIED. +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent **/ -#include "UsbMassImpl.h" +#include "UsbMass.h" /** Execute REQUEST SENSE Command to retrieve sense data from device. @param UsbMass The device whose sense data is requested. - @retval EFI_SUCCESS The command is excuted successfully. + @retval EFI_SUCCESS The command is executed successfully. @retval EFI_DEVICE_ERROR Failed to request sense. @retval EFI_NO_RESPONSE The device media doesn't response this request. @retval EFI_INVALID_PARAMETER The command has some invalid parameters. @@ -50,7 +44,7 @@ UsbBootRequestSense ( SenseCmd.OpCode = USB_BOOT_REQUEST_SENSE_OPCODE; SenseCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); - SenseCmd.AllocLen = sizeof (USB_BOOT_REQUEST_SENSE_DATA); + SenseCmd.AllocLen = (UINT8) sizeof (USB_BOOT_REQUEST_SENSE_DATA); Status = Transport->ExecCommand ( UsbMass->Context, @@ -65,6 +59,9 @@ UsbBootRequestSense ( ); if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) { DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult)); + if (!EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } return Status; } @@ -77,7 +74,14 @@ UsbBootRequestSense ( switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) { case USB_BOOT_SENSE_NO_SENSE: - Status = EFI_NO_RESPONSE; + if (SenseData.Asc == USB_BOOT_ASC_NO_ADDITIONAL_SENSE_INFORMATION) { + // + // It is not an error if a device does not have additional sense information + // + Status = EFI_SUCCESS; + } else { + Status = EFI_NO_RESPONSE; + } break; case USB_BOOT_SENSE_RECOVERED: @@ -89,10 +93,10 @@ UsbBootRequestSense ( case USB_BOOT_SENSE_NOT_READY: Status = EFI_DEVICE_ERROR; - if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) { + if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) { Media->MediaPresent = FALSE; Status = EFI_NO_MEDIA; - } else if (SenseData.ASC == USB_BOOT_ASC_NOT_READY) { + } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) { Status = EFI_NOT_READY; } break; @@ -103,13 +107,17 @@ UsbBootRequestSense ( case USB_BOOT_SENSE_UNIT_ATTENTION: Status = EFI_DEVICE_ERROR; - if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) { + if (SenseData.Asc == USB_BOOT_ASC_MEDIA_CHANGE) { // // If MediaChange, reset ReadOnly and new MediaId // Status = EFI_MEDIA_CHANGED; Media->ReadOnly = FALSE; Media->MediaId++; + } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) { + Status = EFI_NOT_READY; + } else if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) { + Status = EFI_NOT_READY; } break; @@ -123,11 +131,12 @@ UsbBootRequestSense ( break; } - DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n", + DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with error code (%x) sense key %x/%x/%x\n", Status, + SenseData.ErrorCode, USB_BOOT_SENSE_KEY (SenseData.SenseKey), - SenseData.ASC, - SenseData.ASCQ + SenseData.Asc, + SenseData.Ascq )); return Status; @@ -149,7 +158,7 @@ UsbBootRequestSense ( @param DataLen The length of expected data @param Timeout The timeout used to transfer - @retval EFI_SUCCESS Command is excuted successfully + @retval EFI_SUCCESS Command is executed successfully @retval Others Command execution failed. **/ @@ -180,6 +189,12 @@ UsbBootExecCmd ( Timeout, &CmdResult ); + + if (Status == EFI_TIMEOUT) { + DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd\n", Status, *(UINT8 *)Cmd)); + return EFI_TIMEOUT; + } + // // If ExecCommand() returns no error and CmdResult is success, // then the commnad transfer is successful. @@ -188,12 +203,10 @@ UsbBootExecCmd ( return EFI_SUCCESS; } - DEBUG ((EFI_D_INFO, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n", - *(UINT8 *)Cmd ,Status)); - // // If command execution failed, then retrieve error info via sense request. // + DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd (Result = %x)\n", Status, *(UINT8 *)Cmd, CmdResult)); return UsbBootRequestSense (UsbMass); } @@ -205,7 +218,7 @@ UsbBootExecCmd ( If the device isn't ready, wait for it. If the device is ready and error occurs, retry the command again until it exceeds the limit of retrial times. - + @param UsbMass The device to issue commands to @param Cmd The command to execute @param CmdLen The length of the command @@ -215,7 +228,7 @@ UsbBootExecCmd ( @param Timeout The timeout used to transfer @retval EFI_SUCCESS The command is executed successfully. - @retval EFI_MEDIA_CHANGED The device media has been changed. + @retval EFI_NO_MEDIA The device media is removed. @retval Others Command execution failed after retrial. **/ @@ -232,11 +245,30 @@ UsbBootExecCmdWithRetry ( { EFI_STATUS Status; UINTN Retry; + EFI_EVENT TimeoutEvt; + + Retry = 0; + Status = EFI_SUCCESS; + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvt + ); + if (EFI_ERROR (Status)) { + return Status; + } - Status = EFI_SUCCESS; - - for (Retry = 0; Retry < USB_BOOT_COMMAND_RETRY; Retry++) { + Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(60)); + if (EFI_ERROR (Status)) { + goto EXIT; + } + // + // Execute the cmd and retry if it fails. + // + while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) { Status = UsbBootExecCmd ( UsbMass, Cmd, @@ -246,17 +278,29 @@ UsbBootExecCmdWithRetry ( DataLen, Timeout ); - if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED) { + if (Status == EFI_SUCCESS || Status == EFI_NO_MEDIA) { break; } // - // If the device isn't ready, just wait for it without limit on retrial times. + // If the sense data shows the drive is not ready, we need execute the cmd again. + // We limit the upper boundary to 60 seconds. // if (Status == EFI_NOT_READY) { - Retry = 0; + continue; + } + // + // If the status is other error, then just retry 5 times. + // + if (Retry++ >= USB_BOOT_COMMAND_RETRY) { + break; } } +EXIT: + if (TimeoutEvt != NULL) { + gBS->CloseEvent (TimeoutEvt); + } + return Status; } @@ -285,7 +329,7 @@ UsbBootIsUnitReady ( return UsbBootExecCmdWithRetry ( UsbMass, &TestCmd, - sizeof (USB_BOOT_TEST_UNIT_READY_CMD), + (UINT8) sizeof (USB_BOOT_TEST_UNIT_READY_CMD), EfiUsbNoData, NULL, 0, @@ -310,25 +354,24 @@ UsbBootInquiry ( ) { USB_BOOT_INQUIRY_CMD InquiryCmd; - USB_BOOT_INQUIRY_DATA InquiryData; EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; Media = &(UsbMass->BlockIoMedia); ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD)); - ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA)); + ZeroMem (&UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA)); InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE; InquiryCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); - InquiryCmd.AllocLen = sizeof (InquiryData); + InquiryCmd.AllocLen = (UINT8) sizeof (USB_BOOT_INQUIRY_DATA); Status = UsbBootExecCmdWithRetry ( UsbMass, &InquiryCmd, - sizeof (USB_BOOT_INQUIRY_CMD), + (UINT8) sizeof (USB_BOOT_INQUIRY_CMD), EfiUsbDataIn, - &InquiryData, + &UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA), USB_BOOT_GENERAL_CMD_TIMEOUT ); @@ -340,8 +383,8 @@ UsbBootInquiry ( // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit // from the inquiry data. // - UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (InquiryData.Pdt)); - Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (InquiryData.Removable)); + UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (UsbMass->InquiryData.Pdt)); + Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (UsbMass->InquiryData.Removable)); // // Set block size to the default value of 512 Bytes, in case no media is present at first time. // @@ -350,6 +393,87 @@ UsbBootInquiry ( return Status; } +/** + Execute READ CAPACITY 16 bytes command to request information regarding + the capacity of the installed medium of the device. + + This function executes READ CAPACITY 16 bytes command to get the capacity + of the USB mass storage media, including the presence, block size, + and last block number. + + @param UsbMass The device to retireve disk gemotric. + + @retval EFI_SUCCESS The disk geometry is successfully retrieved. + @retval EFI_NOT_READY The returned block size is zero. + @retval Other READ CAPACITY 16 bytes command execution failed. + +**/ +EFI_STATUS +UsbBootReadCapacity16 ( + IN USB_MASS_DEVICE *UsbMass + ) +{ + UINT8 CapacityCmd[16]; + EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData; + EFI_BLOCK_IO_MEDIA *Media; + EFI_STATUS Status; + UINT32 BlockSize; + + Media = &UsbMass->BlockIoMedia; + + Media->MediaPresent = FALSE; + Media->LastBlock = 0; + Media->BlockSize = 0; + + ZeroMem (CapacityCmd, sizeof (CapacityCmd)); + ZeroMem (&CapacityData, sizeof (CapacityData)); + + CapacityCmd[0] = EFI_SCSI_OP_READ_CAPACITY16; + CapacityCmd[1] = 0x10; + // + // Partial medium indicator, set the bytes 2 ~ 9 of the Cdb as ZERO. + // + ZeroMem ((CapacityCmd + 2), 8); + + CapacityCmd[13] = sizeof (CapacityData); + + Status = UsbBootExecCmdWithRetry ( + UsbMass, + CapacityCmd, + (UINT8) sizeof (CapacityCmd), + EfiUsbDataIn, + &CapacityData, + sizeof (CapacityData), + USB_BOOT_GENERAL_CMD_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the information on media presence, block size, and last block number + // from READ CAPACITY data. + // + Media->MediaPresent = TRUE; + Media->LastBlock = SwapBytes64 (ReadUnaligned64 ((CONST UINT64 *) &(CapacityData.LastLba7))); + + BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) &(CapacityData.BlockSize3))); + + Media->LowestAlignedLba = (CapacityData.LowestAlignLogic2 << 8) | + CapacityData.LowestAlignLogic1; + Media->LogicalBlocksPerPhysicalBlock = (1 << CapacityData.LogicPerPhysical); + if (BlockSize == 0) { + // + // Get sense data + // + return UsbBootRequestSense (UsbMass); + } else { + Media->BlockSize = BlockSize; + } + + return Status; +} + /** Execute READ CAPACITY command to request information regarding @@ -364,7 +488,7 @@ UsbBootInquiry ( @retval EFI_SUCCESS The disk geometry is successfully retrieved. @retval EFI_NOT_READY The returned block size is zero. @retval Other READ CAPACITY command execution failed. - + **/ EFI_STATUS UsbBootReadCapacity ( @@ -375,6 +499,7 @@ UsbBootReadCapacity ( USB_BOOT_READ_CAPACITY_DATA CapacityData; EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; + UINT32 BlockSize; Media = &UsbMass->BlockIoMedia; @@ -387,7 +512,7 @@ UsbBootReadCapacity ( Status = UsbBootExecCmdWithRetry ( UsbMass, &CapacityCmd, - sizeof (USB_BOOT_READ_CAPACITY_CMD), + (UINT8) sizeof (USB_BOOT_READ_CAPACITY_CMD), EfiUsbDataIn, &CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA), @@ -403,16 +528,25 @@ UsbBootReadCapacity ( // Media->MediaPresent = TRUE; Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba)); - Media->BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen)); - if (Media->BlockSize == 0) { - return EFI_NOT_READY; + BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen)); + if (BlockSize == 0) { + // + // Get sense data + // + return UsbBootRequestSense (UsbMass); + } else { + Media->BlockSize = BlockSize; } - DEBUG ((EFI_D_INFO, "UsbBootReadCapacity Success LBA=%ld BlockSize=%d\n", - Media->LastBlock, Media->BlockSize)); + if (Media->LastBlock == 0xFFFFFFFF) { + Status = UsbBootReadCapacity16 (UsbMass); + if (!EFI_ERROR (Status)) { + UsbMass->Cdb16Byte = TRUE; + } + } - return EFI_SUCCESS; + return Status; } /** @@ -450,7 +584,7 @@ UsbScsiModeSense ( Status = UsbBootExecCmdWithRetry ( UsbMass, &ModeSenseCmd, - sizeof (USB_SCSI_MODE_SENSE6_CMD), + (UINT8) sizeof (USB_SCSI_MODE_SENSE6_CMD), EfiUsbDataIn, &ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER), @@ -492,10 +626,8 @@ UsbBootGetParams ( { EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; - UINT8 CmdSet; Media = &(UsbMass->BlockIoMedia); - CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass; Status = UsbBootInquiry (UsbMass); if (EFI_ERROR (Status)) { @@ -503,6 +635,18 @@ UsbBootGetParams ( return Status; } + // + // According to USB Mass Storage Specification for Bootability, only following + // 4 Peripheral Device Types are in spec. + // + if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) && + (UsbMass->Pdt != USB_PDT_CDROM) && + (UsbMass->Pdt != USB_PDT_OPTICAL) && + (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) { + DEBUG ((EFI_D_ERROR, "UsbBootGetParams: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt)); + return EFI_UNSUPPORTED; + } + // // Don't use the Removable bit in inquiry data to test whether the media // is removable because many flash disks wrongly set this bit. @@ -518,18 +662,9 @@ UsbBootGetParams ( Media->BlockSize = 0x0800; } - if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) { - // - // ModeSense is required for the device with PDT of 0x00/0x07/0x0E, - // which is from [MassStorageBootabilitySpec-Page7]. - // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI - // could get the information of WriteProtected. - // Since not all device support this command, so skip if fail. - // - UsbScsiModeSense (UsbMass); - } + Status = UsbBootDetectMedia (UsbMass); - return UsbBootReadCapacity (UsbMass); + return Status; } @@ -550,7 +685,6 @@ UsbBootDetectMedia ( EFI_BLOCK_IO_MEDIA OldMedia; EFI_BLOCK_IO_MEDIA *Media; UINT8 CmdSet; - EFI_TPL OldTpl; EFI_STATUS Status; Media = &UsbMass->BlockIoMedia; @@ -561,29 +695,48 @@ UsbBootDetectMedia ( Status = UsbBootIsUnitReady (UsbMass); if (EFI_ERROR (Status)) { - goto ON_ERROR; + DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status)); } - if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) { + // + // Status could be: + // EFI_SUCCESS: all good. + // EFI_NO_MEDIA: media is not present. + // others: HW error. + // For either EFI_NO_MEDIA, or HW error, skip to get WriteProtected and capacity information. + // + if (!EFI_ERROR (Status)) { + if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) { + // + // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E, + // according to Section 4 of USB Mass Storage Specification for Bootability. + // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI + // could get the information of Write Protected. + // Since not all device support this command, skip if fail. + // + UsbScsiModeSense (UsbMass); + } + + Status = UsbBootReadCapacity (UsbMass); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status)); + } + } + + if (EFI_ERROR (Status) && Status != EFI_NO_MEDIA) { // - // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E, - // according to Section 4 of USB Mass Storage Specification for Bootability. - // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI - // could get the information of Write Protected. - // Since not all device support this command, skip if fail. + // For NoMedia, BlockIo is still needed. // - UsbScsiModeSense (UsbMass); + return Status; } - Status = UsbBootReadCapacity (UsbMass); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status)); - goto ON_ERROR; + // + // Simply reject device whose block size is unacceptable small (==0) or large (>64K). + // + if ((Media->BlockSize == 0) || (Media->BlockSize > USB_BOOT_MAX_CARRY_SIZE)) { + return EFI_DEVICE_ERROR; } - return EFI_SUCCESS; - -ON_ERROR: // // Detect whether it is necessary to reinstall the Block I/O Protocol. // @@ -599,12 +752,15 @@ ON_ERROR: (Media->LastBlock != OldMedia.LastBlock)) { // - // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY. - // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface(). - // - OldTpl = EfiGetCurrentTpl (); - gBS->RestoreTPL (TPL_CALLBACK); + // This function is called from: + // Block I/O Protocol APIs, which run at TPL_CALLBACK. + // DriverBindingStart(), which raises to TPL_CALLBACK. + ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK); + // + // When it is called from DriverBindingStart(), below reinstall fails. + // So ignore the return status check. + // gBS->ReinstallProtocolInterface ( UsbMass->Controller, &gEfiBlockIoProtocolGuid, @@ -612,11 +768,8 @@ ON_ERROR: &UsbMass->BlockIo ); - ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK); - gBS->RaiseTPL (OldTpl); - // - // Update MediaId after reinstalling Block I/O Protocol. + // Reset MediaId after reinstalling Block I/O Protocol. // if (Media->MediaPresent != OldMedia.MediaPresent) { if (Media->MediaPresent) { @@ -631,6 +784,8 @@ ON_ERROR: (Media->LastBlock != OldMedia.LastBlock)) { Media->MediaId++; } + + Status = Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA; } return Status; @@ -638,33 +793,37 @@ ON_ERROR: /** - Read some blocks from the device. + Read or write some blocks from the device. - @param UsbMass The USB mass storage device to read from + @param UsbMass The USB mass storage device to access + @param Write TRUE for write operation. @param Lba The start block number - @param TotalBlock Total block number to read - @param Buffer The buffer to read to + @param TotalBlock Total block number to read or write + @param Buffer The buffer to read to or write from - @retval EFI_SUCCESS Data are read into the buffer - @retval Others Failed to read all the data + @retval EFI_SUCCESS Data are read into the buffer or writen into the device. + @retval Others Failed to read or write all the data **/ EFI_STATUS -UsbBootReadBlocks ( +UsbBootReadWriteBlocks ( IN USB_MASS_DEVICE *UsbMass, + IN BOOLEAN Write, IN UINT32 Lba, IN UINTN TotalBlock, - OUT UINT8 *Buffer + IN OUT UINT8 *Buffer ) { - USB_BOOT_READ10_CMD ReadCmd; - EFI_STATUS Status; - UINT16 Count; - UINT32 BlockSize; - UINT32 ByteSize; - UINT32 Timeout; + USB_BOOT_READ_WRITE_10_CMD Cmd; + EFI_STATUS Status; + UINT32 Count; + UINT32 CountMax; + UINT32 BlockSize; + UINT32 ByteSize; + UINT32 Timeout; BlockSize = UsbMass->BlockIoMedia.BlockSize; + CountMax = USB_BOOT_MAX_CARRY_SIZE / BlockSize; Status = EFI_SUCCESS; while (TotalBlock > 0) { @@ -673,8 +832,9 @@ UsbBootReadBlocks ( // on the device. We must split the total block because the READ10 // command only has 16 bit transfer length (in the unit of block). // - Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS); - ByteSize = (UINT32)Count * BlockSize; + Count = (UINT32)MIN (TotalBlock, CountMax); + Count = MIN (MAX_UINT16, Count); + ByteSize = Count * BlockSize; // // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1] @@ -684,18 +844,18 @@ UsbBootReadBlocks ( // // Fill in the command then execute // - ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD)); + ZeroMem (&Cmd, sizeof (USB_BOOT_READ_WRITE_10_CMD)); - ReadCmd.OpCode = USB_BOOT_READ10_OPCODE; - ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); - WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba)); - WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count)); + Cmd.OpCode = Write ? USB_BOOT_WRITE10_OPCODE : USB_BOOT_READ10_OPCODE; + Cmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); + WriteUnaligned32 ((UINT32 *) Cmd.Lba, SwapBytes32 (Lba)); + WriteUnaligned16 ((UINT16 *) Cmd.TransferLen, SwapBytes16 ((UINT16)Count)); Status = UsbBootExecCmdWithRetry ( UsbMass, - &ReadCmd, - sizeof (USB_BOOT_READ10_CMD), - EfiUsbDataIn, + &Cmd, + (UINT8) sizeof (USB_BOOT_READ_WRITE_10_CMD), + Write ? EfiUsbDataOut : EfiUsbDataIn, Buffer, ByteSize, Timeout @@ -703,54 +863,58 @@ UsbBootReadBlocks ( if (EFI_ERROR (Status)) { return Status; } - + DEBUG (( + DEBUG_BLKIO, "UsbBoot%sBlocks: LBA (0x%lx), Blk (0x%x)\n", + Write ? L"Write" : L"Read", + Lba, Count + )); Lba += Count; - Buffer += Count * BlockSize; + Buffer += ByteSize; TotalBlock -= Count; } return Status; } - /** - Write some blocks to the device. + Read or write some blocks from the device by SCSI 16 byte cmd. - @param UsbMass The USB mass storage device to write to + @param UsbMass The USB mass storage device to access + @param Write TRUE for write operation. @param Lba The start block number - @param TotalBlock Total block number to write - @param Buffer Pointer to the source buffer for the data. - - @retval EFI_SUCCESS Data are written into the buffer - @retval Others Failed to write all the data + @param TotalBlock Total block number to read or write + @param Buffer The buffer to read to or write from + @retval EFI_SUCCESS Data are read into the buffer or writen into the device. + @retval Others Failed to read or write all the data **/ EFI_STATUS -UsbBootWriteBlocks ( - IN USB_MASS_DEVICE *UsbMass, - IN UINT32 Lba, - IN UINTN TotalBlock, - IN UINT8 *Buffer +UsbBootReadWriteBlocks16 ( + IN USB_MASS_DEVICE *UsbMass, + IN BOOLEAN Write, + IN UINT64 Lba, + IN UINTN TotalBlock, + IN OUT UINT8 *Buffer ) { - USB_BOOT_WRITE10_CMD WriteCmd; - EFI_STATUS Status; - UINT16 Count; - UINT32 BlockSize; - UINT32 ByteSize; - UINT32 Timeout; + UINT8 Cmd[16]; + EFI_STATUS Status; + UINT32 Count; + UINT32 CountMax; + UINT32 BlockSize; + UINT32 ByteSize; + UINT32 Timeout; BlockSize = UsbMass->BlockIoMedia.BlockSize; + CountMax = USB_BOOT_MAX_CARRY_SIZE / BlockSize; Status = EFI_SUCCESS; while (TotalBlock > 0) { // - // Split the total blocks into smaller pieces to ease the pressure - // on the device. We must split the total block because the WRITE10 - // command only has 16 bit transfer length (in the unit of block). + // Split the total blocks into smaller pieces. // - Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS); - ByteSize = (UINT32)Count * BlockSize; + Count = (UINT32)MIN (TotalBlock, CountMax); + ByteSize = Count * BlockSize; // // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1] @@ -758,20 +922,20 @@ UsbBootWriteBlocks ( Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT; // - // Fill in the write10 command block + // Fill in the command then execute // - ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD)); + ZeroMem (Cmd, sizeof (Cmd)); - WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE; - WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); - WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba)); - WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count)); + Cmd[0] = Write ? EFI_SCSI_OP_WRITE16 : EFI_SCSI_OP_READ16; + Cmd[1] = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0)); + WriteUnaligned64 ((UINT64 *) &Cmd[2], SwapBytes64 (Lba)); + WriteUnaligned32 ((UINT32 *) &Cmd[10], SwapBytes32 (Count)); Status = UsbBootExecCmdWithRetry ( UsbMass, - &WriteCmd, - sizeof (USB_BOOT_WRITE10_CMD), - EfiUsbDataOut, + Cmd, + (UINT8) sizeof (Cmd), + Write ? EfiUsbDataOut : EfiUsbDataIn, Buffer, ByteSize, Timeout @@ -779,16 +943,19 @@ UsbBootWriteBlocks ( if (EFI_ERROR (Status)) { return Status; } - + DEBUG (( + DEBUG_BLKIO, "UsbBoot%sBlocks16: LBA (0x%lx), Blk (0x%x)\n", + Write ? L"Write" : L"Read", + Lba, Count + )); Lba += Count; - Buffer += Count * BlockSize; + Buffer += ByteSize; TotalBlock -= Count; } return Status; } - /** Use the USB clear feature control transfer to clear the endpoint stall condition.