X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FBus%2FUsb%2FUsbMassStorageDxe%2FUsbMassImpl.c;h=8c27e18cdb8754151221d8a00ed943267a9953a2;hp=724246d9f1d9c79e7aaac57febbdc8a00e66af17;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=7df7393feb90e87c32f5473af14eec7562b09ce3 diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c index 724246d9f1..8c27e18cdb 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c @@ -1,37 +1,45 @@ /** @file + USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol. - The implementation of USB mass storage class device driver. - The command set supported is "USB Mass Storage Specification - for Bootability". - -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" -USB_MASS_TRANSPORT *mUsbMassTransport[] = { +#define USB_MASS_TRANSPORT_COUNT 3 +// +// Array of USB transport interfaces. +// +USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = { &mUsbCbi0Transport, &mUsbCbi1Transport, &mUsbBotTransport, +}; + +EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = { + USBMassDriverBindingSupported, + USBMassDriverBindingStart, + USBMassDriverBindingStop, + 0x11, + NULL, NULL }; /** - Reset the block device. ExtendedVerification is ignored for this. + Reset the block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. - @param This The BLOCK IO protocol - @param ExtendedVerification Whether to execute extended verification. + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. - @retval EFI_SUCCESS The device is successfully reseted. - @retval Others Failed to reset the device. + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. **/ EFI_STATUS @@ -45,9 +53,13 @@ UsbMassReset ( EFI_TPL OldTpl; EFI_STATUS Status; - OldTpl = gBS->RaiseTPL (USB_MASS_TPL); + // + // Raise TPL to TPL_CALLBACK to serialize all its operations + // to protect shared data structures. + // + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This); Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification); gBS->RestoreTPL (OldTpl); @@ -56,22 +68,27 @@ UsbMassReset ( } /** - Read some blocks of data from the block device. - - @param This The Block IO protocol - @param MediaId The media's ID of the device for current request - @param Lba The start block number - @param BufferSize The size of buffer to read data in - @param Buffer The buffer to read data to - - @retval EFI_SUCCESS The data is successfully read - @retval EFI_NO_MEDIA Media isn't present - @retval EFI_MEDIA_CHANGED The device media has been changed, that is, - MediaId changed - @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is - NULL. - @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block - size, or overflow the last block number. + Reads the requested number of blocks from the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to read from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. **/ EFI_STATUS @@ -90,34 +107,48 @@ UsbMassReadBlocks ( EFI_TPL OldTpl; UINTN TotalBlock; - OldTpl = gBS->RaiseTPL (USB_MASS_TPL); - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This); - Media = &UsbMass->BlockIoMedia; - // - // First, validate the parameters + // Raise TPL to TPL_CALLBACK to serialize all its operations + // to protect shared data structures. // - if ((Buffer == NULL) || (BufferSize == 0)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This); + Media = &UsbMass->BlockIoMedia; // // If it is a removable media, such as CD-Rom or Usb-Floppy, - // need to detect the media before each rw. While some of + // need to detect the media before each read/write. While some of // Usb-Flash is marked as removable media. // - // - if (Media->RemovableMedia == TRUE) { + if (Media->RemovableMedia) { Status = UsbBootDetectMedia (UsbMass); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status)); goto ON_EXIT; } } + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; + goto ON_EXIT; + } + + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + goto ON_EXIT; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto ON_EXIT; + } + + if (Buffer == NULL) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + // - // Make sure BlockSize and LBA is consistent with BufferSize + // BufferSize must be a multiple of the intrinsic block size of the device. // if ((BufferSize % Media->BlockSize) != 0) { Status = EFI_BAD_BUFFER_SIZE; @@ -126,22 +157,20 @@ UsbMassReadBlocks ( TotalBlock = BufferSize / Media->BlockSize; + // + // Make sure the range to read is valid. + // if (Lba + TotalBlock - 1 > Media->LastBlock) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } - if (!(Media->MediaPresent)) { - Status = EFI_NO_MEDIA; - goto ON_EXIT; - } - - if (MediaId != Media->MediaId) { - Status = EFI_MEDIA_CHANGED; - goto ON_EXIT; + if (UsbMass->Cdb16Byte) { + Status = UsbBootReadWriteBlocks16 (UsbMass, FALSE, Lba, TotalBlock, Buffer); + } else { + Status = UsbBootReadWriteBlocks (UsbMass, FALSE, (UINT32) Lba, TotalBlock, Buffer); } - Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status)); UsbMassReset (This, TRUE); @@ -154,22 +183,28 @@ ON_EXIT: /** - Write some blocks of data to the block device. - - @param This The Block IO protocol - @param MediaId The media's ID of the device for current request - @param Lba The start block number - @param BufferSize The size of buffer to write data to - @param Buffer The buffer to write data to - - @retval EFI_SUCCESS The data is successfully written - @retval EFI_NO_MEDIA Media isn't present - @retval EFI_MEDIA_CHANGED The device media has been changed, that is, - MediaId changed - @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is - NULL. - @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block - size, + Writes a specified number of blocks to the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer Pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. **/ EFI_STATUS @@ -188,54 +223,61 @@ UsbMassWriteBlocks ( EFI_TPL OldTpl; UINTN TotalBlock; - OldTpl = gBS->RaiseTPL (USB_MASS_TPL); - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This); - Media = &UsbMass->BlockIoMedia; - // - // First, validate the parameters + // Raise TPL to TPL_CALLBACK to serialize all its operations + // to protect shared data structures. // - if ((Buffer == NULL) || (BufferSize == 0)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This); + Media = &UsbMass->BlockIoMedia; // // If it is a removable media, such as CD-Rom or Usb-Floppy, - // need to detect the media before each rw. While some of - // Usb-Flash is marked as removable media. + // need to detect the media before each read/write. Some of + // USB Flash is marked as removable media. // - // - if (Media->RemovableMedia == TRUE) { + if (Media->RemovableMedia) { Status = UsbBootDetectMedia (UsbMass); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status)); goto ON_EXIT; } } - // - // Make sure BlockSize and LBA is consistent with BufferSize - // - if ((BufferSize % Media->BlockSize) != 0) { - Status = EFI_BAD_BUFFER_SIZE; + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; goto ON_EXIT; } - TotalBlock = BufferSize / Media->BlockSize; + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + goto ON_EXIT; + } - if (Lba + TotalBlock - 1 > Media->LastBlock) { + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto ON_EXIT; + } + + if (Buffer == NULL) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } - if (!(Media->MediaPresent)) { - Status = EFI_NO_MEDIA; + // + // BufferSize must be a multiple of the intrinsic block size of the device. + // + if ((BufferSize % Media->BlockSize) != 0) { + Status = EFI_BAD_BUFFER_SIZE; goto ON_EXIT; } - if (MediaId != Media->MediaId) { - Status = EFI_MEDIA_CHANGED; + TotalBlock = BufferSize / Media->BlockSize; + + // + // Make sure the range to write is valid. + // + if (Lba + TotalBlock - 1 > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } @@ -243,7 +285,12 @@ UsbMassWriteBlocks ( // Try to write the data even the device is marked as ReadOnly, // and clear the status should the write succeed. // - Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer); + if (UsbMass->Cdb16Byte) { + Status = UsbBootReadWriteBlocks16 (UsbMass, TRUE, Lba, TotalBlock, Buffer); + } else { + Status = UsbBootReadWriteBlocks (UsbMass, TRUE, (UINT32) Lba, TotalBlock, Buffer); + } + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status)); UsbMassReset (This, TRUE); @@ -255,12 +302,17 @@ ON_EXIT: } /** - Flush the cached writes to disks. USB mass storage device doesn't - support write cache, so return EFI_SUCCESS directly. + Flushes all modified data to a physical block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks(). + USB mass storage device doesn't support write cache, + so return EFI_SUCCESS directly. - @param This The BLOCK IO protocol + @param This Indicates a pointer to the calling context. - @retval EFI_SUCCESS Always returns success + @retval EFI_SUCCESS All outstanding data were written correctly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. + @retval EFI_NO_MEDIA There is no media in the device. **/ EFI_STATUS @@ -273,12 +325,11 @@ UsbMassFlushBlocks ( } /** - Retrieve the media parameters such as disk geometric for the - device's BLOCK IO protocol. + Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol. @param UsbMass The USB mass storage device - @retval EFI_SUCCESS The media parameters is updated successfully. + @retval EFI_SUCCESS The media parameters are updated successfully. @retval Others Failed to get the media parameters. **/ @@ -289,23 +340,12 @@ UsbMassInitMedia ( { EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; - UINTN Index; Media = &UsbMass->BlockIoMedia; // - // Initialize the MediaPrsent/ReadOnly and others to the default. - // We are not forced to get it right at this time, check UEFI2.0 - // spec for more information: - // - // MediaPresent: This field shows the media present status as - // of the most recent ReadBlocks or WriteBlocks call. - // - // ReadOnly : This field shows the read-only status as of the - // recent WriteBlocks call. - // - // but remember to update MediaId/MediaPresent/ReadOnly status - // after ReadBlocks and WriteBlocks + // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec, + // section for Block I/O Protocol. // Media->MediaPresent = FALSE; Media->LogicalPartition = FALSE; @@ -314,41 +354,32 @@ UsbMassInitMedia ( Media->IoAlign = 0; Media->MediaId = 1; - // - // Some device may spend several seconds before it is ready. - // Try several times before giving up. Wait 5s at most. - // - Status = EFI_SUCCESS; - - for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) { - - Status = UsbBootGetParams (UsbMass); - if ((Status != EFI_MEDIA_CHANGED) - && (Status != EFI_NOT_READY) - && (Status != EFI_TIMEOUT)) { - break; - } - - Status = UsbBootIsUnitReady (UsbMass); - if (EFI_ERROR (Status)) { - gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1)); - } - + Status = UsbBootGetParams (UsbMass); + DEBUG ((DEBUG_INFO, "UsbMassInitMedia: UsbBootGetParams (%r)\n", Status)); + if (Status == EFI_MEDIA_CHANGED) { + // + // Some USB storage devices may report MEDIA_CHANGED sense key when hot-plugged. + // Treat it as SUCCESS + // + Status = EFI_SUCCESS; } - return Status; } /** - Initilize the transport. + Initilize the USB Mass Storage transport. + + This function tries to find the matching USB Mass Storage transport + protocol for USB device. If found, initializes the matching transport. @param This The USB mass driver's driver binding. @param Controller The device to test. @param Transport The pointer to pointer to USB_MASS_TRANSPORT. - @param Context The passing parameter. + @param Context The parameter for USB_MASS_DEVICE.Context. @param MaxLun Get the MaxLun if is BOT dev. @retval EFI_SUCCESS The initialization is successful. + @retval EFI_UNSUPPORTED No matching transport protocol is found. @retval Others Failed to initialize dev. **/ @@ -365,7 +396,7 @@ UsbMassInitTransport ( EFI_USB_INTERFACE_DESCRIPTOR Interface; UINT8 Index; EFI_STATUS Status; - + Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, @@ -376,19 +407,23 @@ UsbMassInitTransport ( ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: OpenUsbIoProtocol By Driver (%r)\n", Status)); return Status; } - + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status)); goto ON_EXIT; } - + Status = EFI_UNSUPPORTED; - for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) { + // + // Traverse the USB_MASS_TRANSPORT arrary and try to find the + // matching transport protocol. + // If not found, return EFI_UNSUPPORTED. + // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context. + // + for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) { *Transport = mUsbMassTransport[Index]; if (Interface.InterfaceProtocol == (*Transport)->Protocol) { @@ -398,17 +433,16 @@ UsbMassInitTransport ( } if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: Transport->Init (%r)\n", Status)); goto ON_EXIT; } // - // For bot device, try to get max lun. - // If maxlun=0, then non-lun device, else multi-lun device. + // For BOT device, try to get its max LUN. + // If max LUN is 0, then it is a non-lun device. + // Otherwise, it is a multi-lun device. // if ((*Transport)->Protocol == USB_MASS_STORE_BOT) { (*Transport)->GetMaxLun (*Context, MaxLun); - DEBUG ((EFI_D_INFO, "UsbMassInitTransport: GetMaxLun = %d\n", *MaxLun)); } ON_EXIT: @@ -418,26 +452,26 @@ ON_EXIT: This->DriverBindingHandle, Controller ); - return Status; + return Status; } /** - Usb mass storage driver initializes multi lun. + Initialize data for device that supports multiple LUNSs. - @param This The USB mass driver's driver binding. - @param Controller The device to test. - @param Transport The pointer to USB_MASS_TRANSPORT. - @param Context The passing parameter. - @param DevicePath The remaining device path - @param MaxLun The MaxLun number passed. + @param This The Driver Binding Protocol instance. + @param Controller The device to initialize. + @param Transport Pointer to USB_MASS_TRANSPORT. + @param Context Parameter for USB_MASS_DEVICE.Context. + @param DevicePath The remaining device path. + @param MaxLun The max LUN number. - @retval EFI_SUCCESS Initialization is success. - @retval Other Initialization fails. + @retval EFI_SUCCESS At least one LUN is initialized successfully. + @retval EFI_NOT_FOUND Fail to initialize any of multiple LUNs. **/ EFI_STATUS UsbMassInitMultiLun ( - IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN USB_MASS_TRANSPORT *Transport, IN VOID *Context, @@ -450,20 +484,19 @@ UsbMassInitMultiLun ( DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode; UINT8 Index; EFI_STATUS Status; + EFI_STATUS ReturnStatus; ASSERT (MaxLun > 0); + ReturnStatus = EFI_NOT_FOUND; - for (Index = 0; Index <= MaxLun; Index++) { + for (Index = 0; Index <= MaxLun; Index++) { DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index)); - + UsbIo = NULL; UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE)); - if (UsbMass == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_ERROR; - } - + ASSERT (UsbMass != NULL); + UsbMass->Signature = USB_MASS_SIGNATURE; UsbMass->UsbIo = UsbIo; UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia; @@ -475,45 +508,39 @@ UsbMassInitMultiLun ( UsbMass->Transport = Transport; UsbMass->Context = Context; UsbMass->Lun = Index; - + // - // Get the storage's parameters, such as last block number. - // then install the BLOCK_IO + // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol. // Status = UsbMassInitMedia (UsbMass); - if (!EFI_ERROR (Status)) { - 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, "UsbMassInitMultiLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt)); - goto ON_ERROR; - } - } else if (Status != EFI_NO_MEDIA){ + if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) { DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status)); - goto ON_ERROR; + FreePool (UsbMass); + continue; } // - // Create a device path node of device logic unit, and append it + // Create a device path node for device logic unit, and append it. // LunNode.Header.Type = MESSAGING_DEVICE_PATH; LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP; LunNode.Lun = UsbMass->Lun; - + SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode)); - + UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header); - + if (UsbMass->DevicePath == NULL) { DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n")); - Status = EFI_OUT_OF_RESOURCES; - goto ON_ERROR; + FreePool (UsbMass); + continue; } + InitializeDiskInfo (UsbMass); + // - // Create a UsbMass handle for each lun, and install blockio and devicepath protocols. + // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol. // Status = gBS->InstallMultipleProtocolInterfaces ( &UsbMass->Controller, @@ -521,16 +548,20 @@ UsbMassInitMultiLun ( UsbMass->DevicePath, &gEfiBlockIoProtocolGuid, &UsbMass->BlockIo, + &gEfiDiskInfoProtocolGuid, + &UsbMass->DiskInfo, NULL ); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status)); - goto ON_ERROR; + FreePool (UsbMass->DevicePath); + FreePool (UsbMass); + continue; } // - // Open UsbIo protocol by child to setup a parent-child relationship. + // Open USB I/O Protocol by child to setup a parent-child relationship. // Status = gBS->OpenProtocol ( Controller, @@ -549,51 +580,30 @@ UsbMassInitMultiLun ( UsbMass->DevicePath, &gEfiBlockIoProtocolGuid, &UsbMass->BlockIo, + &gEfiDiskInfoProtocolGuid, + &UsbMass->DiskInfo, NULL ); - goto ON_ERROR; + FreePool (UsbMass->DevicePath); + FreePool (UsbMass); + continue; } - + ReturnStatus = EFI_SUCCESS; DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index)); } - - return EFI_SUCCESS; - -ON_ERROR: - if (UsbMass->DevicePath != NULL) { - gBS->FreePool (UsbMass->DevicePath); - } - if (UsbMass != NULL) { - gBS->FreePool (UsbMass); - } - if (UsbIo != NULL) { - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - UsbMass->Controller - ); - } - // - // If only success to initialize one lun, return success, or else return error - // - if (Index > 0) { - return EFI_SUCCESS; - } else { - return Status; - } + return ReturnStatus; } /** - Initialize No/Unsupported LUN device. + Initialize data for device that does not support multiple LUNSs. - @param This The USB mass driver's driver binding. - @param Controller The device to test. - @param Transport The pointer to USB_MASS_TRANSPORT. - @param Context The passing parameter. + @param This The Driver Binding Protocol instance. + @param Controller The device to initialize. + @param Transport Pointer to USB_MASS_TRANSPORT. + @param Context Parameter for USB_MASS_DEVICE.Context. - @retval EFI_SUCCESS Initialization is success. + @retval EFI_SUCCESS Initialization succeeds. @retval Other Initialization fails. **/ @@ -611,9 +621,8 @@ UsbMassInitNonLun ( UsbIo = NULL; UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE)); - if (UsbMass == NULL) { - return EFI_OUT_OF_RESOURCES; - } + ASSERT (UsbMass != NULL); + Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, @@ -627,7 +636,7 @@ UsbMassInitNonLun ( DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status)); goto ON_ERROR; } - + UsbMass->Signature = USB_MASS_SIGNATURE; UsbMass->Controller = Controller; UsbMass->UsbIo = UsbIo; @@ -639,30 +648,25 @@ UsbMassInitNonLun ( UsbMass->OpticalStorage = FALSE; UsbMass->Transport = Transport; UsbMass->Context = Context; - + // - // Get the storage's parameters, such as last block number. - // then install the BLOCK_IO + // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol. // Status = UsbMassInitMedia (UsbMass); - if (!EFI_ERROR (Status)) { - 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, "UsbMassInitNonLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt)); - goto ON_ERROR; - } - } else if (Status != EFI_NO_MEDIA){ + if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) { DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status)); goto ON_ERROR; } - - Status = gBS->InstallProtocolInterface ( + + InitializeDiskInfo (UsbMass); + + Status = gBS->InstallMultipleProtocolInterfaces ( &Controller, &gEfiBlockIoProtocolGuid, - EFI_NATIVE_INTERFACE, - &UsbMass->BlockIo + &UsbMass->BlockIo, + &gEfiDiskInfoProtocolGuid, + &UsbMass->DiskInfo, + NULL ); if (EFI_ERROR (Status)) { goto ON_ERROR; @@ -672,28 +676,29 @@ UsbMassInitNonLun ( ON_ERROR: if (UsbMass != NULL) { - gBS->FreePool (UsbMass); + FreePool (UsbMass); } - gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - return Status; + if (UsbIo != NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + return Status; } /** Check whether the controller is a supported USB mass storage. - @param This The USB mass driver's driver binding. - @param Controller The device to test against. - @param RemainingDevicePath The remaining device path + @param This The USB mass storage driver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. - @retval EFI_SUCCESS This device is a supported USB mass storage. - @retval EFI_UNSUPPORTED The device isn't supported - @retval Others Some error happened. + @retval EFI_SUCCESS The driver supports this controller. + @retval other This device isn't supported. **/ EFI_STATUS @@ -708,11 +713,8 @@ USBMassDriverBindingSupported ( EFI_USB_INTERFACE_DESCRIPTOR Interface; USB_MASS_TRANSPORT *Transport; EFI_STATUS Status; - INTN Index; + UINTN Index; - // - // Check whether the controller support USB_IO - // Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, @@ -726,7 +728,7 @@ USBMassDriverBindingSupported ( } // - // Get the interface to check the USB class and find a transport + // Get the interface descriptor to check the USB class and find a transport // protocol handler. // Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); @@ -740,7 +742,13 @@ USBMassDriverBindingSupported ( goto ON_EXIT; } - for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) { + // + // Traverse the USB_MASS_TRANSPORT arrary and try to find the + // matching transport method. + // If not found, return EFI_UNSUPPORTED. + // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context. + // + for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) { Transport = mUsbMassTransport[Index]; if (Interface.InterfaceProtocol == Transport->Protocol) { Status = Transport->Init (UsbIo, NULL); @@ -748,31 +756,33 @@ USBMassDriverBindingSupported ( } } - DEBUG ((EFI_D_INFO, "Found a USB mass store device %r\n", Status)); - ON_EXIT: gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); return Status; } - /** - Start the USB mass storage device on the controller. It will - install a BLOCK_IO protocol on the device if everything is OK. + Starts the USB mass storage device with this driver. - @param This The USB mass storage driver binding. - @param Controller The USB mass storage device to start on - @param RemainingDevicePath The remaining device path. + This function consumes USB I/O Portocol, intializes USB mass storage device, + installs Block I/O Protocol, and submits Asynchronous Interrupt + Transfer to manage the USB mass storage device. - @retval EFI_SUCCESS The driver has started on the device. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory - @retval Others Failed to start the driver on the device. + @param This The USB mass storage driver binding protocol. + @param Controller The USB mass storage device to start on + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. + @retval EFI_ALREADY_STARTED This driver has been started. **/ EFI_STATUS @@ -788,31 +798,32 @@ USBMassDriverBindingStart ( VOID *Context; UINT8 MaxLun; EFI_STATUS Status; - + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_TPL OldTpl; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + Transport = NULL; Context = NULL; MaxLun = 0; - // - // Get interface and protocols, initialize transport - // Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status)); - return Status; + goto Exit; } if (MaxLun == 0) { // - // Initialize No/Unsupported LUN device + // Initialize data for device that does not support multiple LUNSs. // - Status = UsbMassInitNonLun(This, Controller, Transport, Context); - if (EFI_ERROR (Status)) { + Status = UsbMassInitNonLun (This, Controller, Transport, Context); + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status)); } } else { // - // Open device path to prepare append Device Logic Unit node. + // Open device path to prepare for appending Device Logic Unit node. // Status = gBS->OpenProtocol ( Controller, @@ -822,26 +833,55 @@ USBMassDriverBindingStart ( Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status)); - return Status; + goto Exit; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status)); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + goto Exit; } // - // Try best to initialize all LUNs, and return success only if one of LUNs successed to initialized. + // Initialize data for device that supports multiple LUNs. + // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully. // - Status = UsbMassInitMultiLun(This, Controller, Transport, Context, DevicePath, MaxLun); + Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun); if (EFI_ERROR (Status)) { - gBS->CloseProtocol ( - Controller, - &gEfiDevicePathProtocolGuid, - This->DriverBindingHandle, - Controller - ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun)); } } +Exit: + gBS->RestoreTPL (OldTpl); return Status; } @@ -855,6 +895,8 @@ USBMassDriverBindingStart ( @param ChildHandleBuffer The buffer of children handle. @retval EFI_SUCCESS The driver stopped from controlling the device. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller. @retval Others Failed to stop the driver **/ @@ -869,17 +911,17 @@ USBMassDriverBindingStop ( { EFI_STATUS Status; USB_MASS_DEVICE *UsbMass; - EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_IO_PROTOCOL *UsbIo; EFI_BLOCK_IO_PROTOCOL *BlockIo; - UINTN Index; - BOOLEAN AllChildrenStopped; + UINTN Index; + BOOLEAN AllChildrenStopped; // - // This a bus driver stop function since multi-lun supported. There are three - // kinds of device handle might be passed, 1st is a handle with devicepath/ - // usbio/blockio installed(non-multi-lun), 2nd is a handle with devicepath/ - // usbio installed(multi-lun root), 3rd is a handle with devicepath/blockio - // installed(multi-lun). + // This is a bus driver stop function since multi-lun is supported. + // There are three kinds of device handles that might be passed: + // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun) + // 2nd is a handle with Device Path & USB I/O installed (multi-lun root) + // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun). // if (NumberOfChildren == 0) { // @@ -893,11 +935,11 @@ USBMassDriverBindingStop ( Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); - + if (EFI_ERROR(Status)) { // - // This is a 2nd type handle(multi-lun root), which only needs close - // devicepath protocol. + // This is a 2nd type handle(multi-lun root), it needs to close devicepath + // and usbio protocol. // gBS->CloseProtocol ( Controller, @@ -905,47 +947,56 @@ USBMassDriverBindingStop ( This->DriverBindingHandle, Controller ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n")); return EFI_SUCCESS; } - + // - // This is a 1st type handle(non-multi-lun), which only needs uninstall - // blockio protocol, close usbio protocol and free mass device. + // This is a 1st type handle(non-multi-lun), which only needs to uninstall + // Block I/O Protocol, close USB I/O Protocol and free mass device. // - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo); - + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo); + // // Uninstall Block I/O protocol from the device handle, // then call the transport protocol to stop itself. // - Status = gBS->UninstallProtocolInterface ( + Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiBlockIoProtocolGuid, - &UsbMass->BlockIo + &UsbMass->BlockIo, + &gEfiDiskInfoProtocolGuid, + &UsbMass->DiskInfo, + NULL ); if (EFI_ERROR (Status)) { return Status; } - + gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); - - UsbMass->Transport->Fini (UsbMass->Context); - gBS->FreePool (UsbMass); - + + UsbMass->Transport->CleanUp (UsbMass->Context); + FreePool (UsbMass); + DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n")); return EFI_SUCCESS; - } + } // // This is a 3rd type handle(multi-lun), which needs uninstall - // blockio and devicepath protocol, close usbio protocol and - // free mass device. + // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and + // free mass device for all children. // AllChildrenStopped = TRUE; @@ -965,31 +1016,33 @@ USBMassDriverBindingStop ( continue; } - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo); gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - ChildHandleBuffer[Index] - ); - + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, UsbMass->DevicePath, &gEfiBlockIoProtocolGuid, &UsbMass->BlockIo, + &gEfiDiskInfoProtocolGuid, + &UsbMass->DiskInfo, NULL ); - + if (EFI_ERROR (Status)) { // - // Fail to uninstall blockio and devicepath protocol, so re-open usbio by child. + // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child. // AllChildrenStopped = FALSE; DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index)); - + gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, @@ -1000,41 +1053,33 @@ USBMassDriverBindingStop ( ); } else { // - // Success to stop this multi-lun handle, so go on next child. + // Succeed to stop this multi-lun handle, so go on with next child. // if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) { - UsbMass->Transport->Fini (UsbMass->Context); + UsbMass->Transport->CleanUp (UsbMass->Context); } - gBS->FreePool (UsbMass); + FreePool (UsbMass); } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } - - DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32)NumberOfChildren)); + + DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren)); return EFI_SUCCESS; } -EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = { - USBMassDriverBindingSupported, - USBMassDriverBindingStart, - USBMassDriverBindingStop, - 0x11, - NULL, - NULL -}; - /** - The entry point for the driver, which will install the driver binding and - component name protocol. + Entrypoint of USB Mass Storage Driver. + + This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding + Protocol together with Component Name Protocols. - @param ImageHandle The image handle of this driver. - @param SystemTable The system table. + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. - @retval EFI_SUCCESS The protocols are installed OK. - @retval Others Failed to install protocols. + @retval EFI_SUCCESS The entry point is executed successfully. **/ EFI_STATUS @@ -1057,6 +1102,7 @@ USBMassStorageEntryPoint ( &gUsbMassStorageComponentName, &gUsbMassStorageComponentName2 ); + ASSERT_EFI_ERROR (Status); - return Status; + return EFI_SUCCESS; }