/** Write by using the Disk IO protocol on the parent device. Lba addresses must be converted to byte offsets. @param[in] This Protocol instance pointer. @param[in] MediaId Id of the media, changes every time the media is replaced. @param[in] Lba The starting Logical Block Address to read from @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[in] Buffer Buffer containing data to be written to device. @retval EFI_SUCCESS The data was written correctly to the device. @retval EFI_WRITE_PROTECTED The device can not be written to. @retval EFI_DEVICE_ERROR The device reported an error while performing the write. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not valid for the device. **/ EFI_STATUS EFIAPI PartitionWriteBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer ) { PARTITION_PRIVATE_DATA *Private; UINT64 Offset; Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); if (BufferSize % Private->BlockSize != 0) { return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE); } Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; if (Offset + BufferSize > Private->End) { return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER); } // // Because some kinds of partition have different block size from their parent // device, we call the Disk IO protocol on the parent device, not the Block IO // protocol // return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer); }
/** Flush the parent Block Device. @param This Protocol instance pointer. @retval EFI_SUCCESS All outstanding data was written to the device @retval EFI_DEVICE_ERROR The device reported an error while writting back the data @retval EFI_NO_MEDIA There is no media in the device. **/ EFI_STATUS EFIAPI PartitionFlushBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This ) { PARTITION_PRIVATE_DATA *Private; Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo); }
/** Reset the Block Device. @param This Protocol instance pointer. @param ExtendedVerification Driver may perform diagnostics on reset. @retval EFI_SUCCESS The device was reset. @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset. **/ EFI_STATUS EFIAPI PartitionReset ( IN EFI_BLOCK_IO_PROTOCOL *This, IN BOOLEAN ExtendedVerification ) { PARTITION_PRIVATE_DATA *Private; Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); return Private->ParentBlockIo->Reset ( Private->ParentBlockIo, ExtendedVerification ); }
/** Stop this driver on ControllerHandle. Support stopping any child handles created by this driver. @param This Protocol instance pointer. @param ControllerHandle Handle of device to stop driver on @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of children is zero stop the entire bus driver. @param ChildHandleBuffer List of Child Handles to Stop. @retval EFI_SUCCESS This driver is removed ControllerHandle @retval other This driver was not removed from this device **/ EFI_STATUS EFIAPI PartitionDriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; UINTN Index; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO2_PROTOCOL *BlockIo2; BOOLEAN AllChildrenStopped; PARTITION_PRIVATE_DATA *Private; EFI_DISK_IO_PROTOCOL *DiskIo; BlockIo = NULL; BlockIo2 = NULL; Private = NULL; if (NumberOfChildren == 0) { // // Close the bus driver // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Close Parent BlockIO2 if has. // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIo2ProtocolGuid, This->DriverBindingHandle, ControllerHandle ); gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); // // Try to locate BlockIo2. // gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIo2ProtocolGuid, (VOID **) &BlockIo2, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo); Status = gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ChildHandleBuffer[Index] ); // // All Software protocols have be freed from the handle so remove it. // Remove the BlockIo Protocol if has. // Remove the BlockIo2 Protocol if has. // if (BlockIo2 != NULL) { BlockIo->FlushBlocks (BlockIo); BlockIo2->FlushBlocksEx (BlockIo2, NULL); Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, &gEfiBlockIo2ProtocolGuid, &Private->BlockIo2, Private->EspGuid, NULL, NULL ); } else { BlockIo->FlushBlocks (BlockIo); Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, Private->EspGuid, NULL, NULL ); } if (EFI_ERROR (Status)) { gBS->OpenProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { FreePool (Private->DevicePath); FreePool (Private); } if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; }
/** Stop this driver on ControllerHandle. Support stopping any child handles created by this driver. @param This Protocol instance pointer. @param ControllerHandle Handle of device to stop driver on @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of children is zero stop the entire bus driver. @param ChildHandleBuffer List of Child Handles to Stop. @retval EFI_SUCCESS This driver is removed ControllerHandle @retval other This driver was not removed from this device **/ EFI_STATUS EFIAPI PartitionDriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; UINTN Index; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO2_PROTOCOL *BlockIo2; BOOLEAN AllChildrenStopped; PARTITION_PRIVATE_DATA *Private; EFI_DISK_IO_PROTOCOL *DiskIo; EFI_GUID *TypeGuid; BlockIo = NULL; BlockIo2 = NULL; Private = NULL; if (NumberOfChildren == 0) { // // In the case of re-entry of the PartitionDriverBindingStop, the // NumberOfChildren may not reflect the actual number of children on the // bus driver. Hence, additional check is needed here. // if (HasChildren (ControllerHandle)) { DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n")); return EFI_DEVICE_ERROR; } // // Close the bus driver // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Close Parent BlockIO2 if has. // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIo2ProtocolGuid, This->DriverBindingHandle, ControllerHandle ); gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); // // Try to locate BlockIo2. // gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIo2ProtocolGuid, (VOID **) &BlockIo2, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo); if (Private->InStop) { // // If the child handle is going to be stopped again during the re-entry // of DriverBindingStop, just do nothing. // break; } Private->InStop = TRUE; BlockIo->FlushBlocks (BlockIo); if (BlockIo2 != NULL) { Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL); DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status)); } else { Status = EFI_SUCCESS; } gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ChildHandleBuffer[Index] ); if (IsZeroGuid (&Private->TypeGuid)) { TypeGuid = NULL; } else { TypeGuid = &Private->TypeGuid; } // // All Software protocols have be freed from the handle so remove it. // Remove the BlockIo Protocol if has. // Remove the BlockIo2 Protocol if has. // if (BlockIo2 != NULL) { // // Some device drivers might re-install the BlockIO(2) protocols for a // media change condition. Therefore, if the FlushBlocksEx returned with // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential // reference of already stopped child handle. // if (Status != EFI_MEDIA_CHANGED) { Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, &gEfiBlockIo2ProtocolGuid, &Private->BlockIo2, &gEfiPartitionInfoProtocolGuid, &Private->PartitionInfo, TypeGuid, NULL, NULL ); } } else { Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, &gEfiPartitionInfoProtocolGuid, &Private->PartitionInfo, TypeGuid, NULL, NULL ); } if (EFI_ERROR (Status)) { Private->InStop = FALSE; gBS->OpenProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { FreePool (Private->DevicePath); FreePool (Private); } if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; if (Status == EFI_MEDIA_CHANGED) { break; } } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; }