3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "UsbBotPeim.h"
15 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList
= {
16 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
21 EFI_PEI_RECOVERY_BLOCK_IO_PPI mRecoveryBlkIoPpi
= {
22 BotGetNumberOfBlockDevices
,
27 EFI_PEI_RECOVERY_BLOCK_IO2_PPI mRecoveryBlkIo2Ppi
= {
28 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
,
29 BotGetNumberOfBlockDevices2
,
34 EFI_PEI_PPI_DESCRIPTOR mPpiList
[2] = {
36 EFI_PEI_PPI_DESCRIPTOR_PPI
,
37 &gEfiPeiVirtualBlockIoPpiGuid
,
41 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
42 &gEfiPeiVirtualBlockIo2PpiGuid
,
48 Detect whether the removable media is present and whether it has changed.
50 @param[in] PeiServices General-purpose services that are available to every
52 @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.
54 @retval EFI_SUCCESS The media status is successfully checked.
55 @retval Other Failed to detect media.
60 IN EFI_PEI_SERVICES
**PeiServices
,
61 IN PEI_BOT_DEVICE
*PeiBotDev
65 Initializes the Usb Bot.
67 @param FileHandle Handle of the file being invoked.
68 @param PeiServices Describes the list of possible PEI Services.
70 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
71 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
76 PeimInitializeUsbBot (
77 IN EFI_PEI_FILE_HANDLE FileHandle
,
78 IN CONST EFI_PEI_SERVICES
**PeiServices
82 UINTN UsbIoPpiInstance
;
83 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
84 PEI_USB_IO_PPI
*UsbIoPpi
;
87 // Shadow this PEIM to run from memory
89 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
94 // locate all usb io PPIs
96 for (UsbIoPpiInstance
= 0; UsbIoPpiInstance
< PEI_FAT_MAX_USB_IO_PPI
; UsbIoPpiInstance
++) {
98 Status
= PeiServicesLocatePpi (
104 if (EFI_ERROR (Status
)) {
109 // Register a notify function
111 return PeiServicesNotifyPpi (&mNotifyList
);
115 UsbIo installation notification function.
117 This function finds out all the current USB IO PPIs in the system and add them
120 @param PeiServices Indirect reference to the PEI Services Table.
121 @param NotifyDesc Address of the notification descriptor data structure.
122 @param InvokePpi Address of the PPI that was invoked.
124 @retval EFI_SUCCESS The function completes successfully.
130 IN EFI_PEI_SERVICES
**PeiServices
,
131 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
135 PEI_USB_IO_PPI
*UsbIoPpi
;
137 UsbIoPpi
= (PEI_USB_IO_PPI
*) InvokePpi
;
139 InitUsbBot (PeiServices
, UsbIoPpi
);
145 Initialize the usb bot device.
147 @param[in] PeiServices General-purpose services that are available to every
149 @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
151 @retval EFI_SUCCESS The usb bot device is initialized successfully.
152 @retval Other Failed to initialize media.
157 IN EFI_PEI_SERVICES
**PeiServices
,
158 IN PEI_USB_IO_PPI
*UsbIoPpi
161 PEI_BOT_DEVICE
*PeiBotDevice
;
163 EFI_USB_INTERFACE_DESCRIPTOR
*InterfaceDesc
;
165 EFI_PHYSICAL_ADDRESS AllocateAddress
;
166 EFI_USB_ENDPOINT_DESCRIPTOR
*EndpointDesc
;
170 // Check its interface
172 Status
= UsbIoPpi
->UsbGetInterfaceDescriptor (
177 if (EFI_ERROR (Status
)) {
181 // Check if it is the BOT device we support
183 if ((InterfaceDesc
->InterfaceClass
!= 0x08) || (InterfaceDesc
->InterfaceProtocol
!= 0x50)) {
185 return EFI_NOT_FOUND
;
188 MemPages
= sizeof (PEI_BOT_DEVICE
) / EFI_PAGE_SIZE
+ 1;
189 Status
= PeiServicesAllocatePages (
194 if (EFI_ERROR (Status
)) {
198 PeiBotDevice
= (PEI_BOT_DEVICE
*) ((UINTN
) AllocateAddress
);
200 PeiBotDevice
->Signature
= PEI_BOT_DEVICE_SIGNATURE
;
201 PeiBotDevice
->UsbIoPpi
= UsbIoPpi
;
202 PeiBotDevice
->AllocateAddress
= (UINTN
) AllocateAddress
;
203 PeiBotDevice
->BotInterface
= InterfaceDesc
;
208 PeiBotDevice
->Media
.DeviceType
= UsbMassStorage
;
209 PeiBotDevice
->Media
.BlockSize
= 0x200;
210 PeiBotDevice
->Media2
.InterfaceType
= MSG_USB_DP
;
211 PeiBotDevice
->Media2
.BlockSize
= 0x200;
212 PeiBotDevice
->Media2
.RemovableMedia
= FALSE
;
213 PeiBotDevice
->Media2
.ReadOnly
= FALSE
;
216 // Check its Bulk-in/Bulk-out endpoint
218 for (Index
= 0; Index
< 2; Index
++) {
219 Status
= UsbIoPpi
->UsbGetEndpointDescriptor (
226 if (EFI_ERROR (Status
)) {
230 if ((EndpointDesc
->EndpointAddress
& 0x80) != 0) {
231 PeiBotDevice
->BulkInEndpoint
= EndpointDesc
;
233 PeiBotDevice
->BulkOutEndpoint
= EndpointDesc
;
238 &(PeiBotDevice
->BlkIoPpi
),
240 sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI
)
243 &(PeiBotDevice
->BlkIo2Ppi
),
245 sizeof (EFI_PEI_RECOVERY_BLOCK_IO2_PPI
)
248 &(PeiBotDevice
->BlkIoPpiList
),
250 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
253 &(PeiBotDevice
->BlkIo2PpiList
),
255 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
257 PeiBotDevice
->BlkIoPpiList
.Ppi
= &PeiBotDevice
->BlkIoPpi
;
258 PeiBotDevice
->BlkIo2PpiList
.Ppi
= &PeiBotDevice
->BlkIo2Ppi
;
260 Status
= PeiUsbInquiry (PeiServices
, PeiBotDevice
);
261 if (EFI_ERROR (Status
)) {
265 Status
= PeiServicesAllocatePages (
270 if (EFI_ERROR (Status
)) {
274 PeiBotDevice
->SensePtr
= (ATAPI_REQUEST_SENSE_DATA
*) ((UINTN
) AllocateAddress
);
276 Status
= PeiServicesInstallPpi (&PeiBotDevice
->BlkIoPpiList
);
278 if (EFI_ERROR (Status
)) {
286 Gets the count of block I/O devices that one specific block driver detects.
288 This function is used for getting the count of block I/O devices that one
289 specific block driver detects. To the PEI ATAPI driver, it returns the number
290 of all the detected ATAPI devices it detects during the enumeration process.
291 To the PEI legacy floppy driver, it returns the number of all the legacy
292 devices it finds during its enumeration process. If no device is detected,
293 then the function will return zero.
295 @param[in] PeiServices General-purpose services that are available
297 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
299 @param[out] NumberBlockDevices The number of block I/O devices discovered.
301 @retval EFI_SUCCESS Operation performed successfully.
306 BotGetNumberOfBlockDevices (
307 IN EFI_PEI_SERVICES
**PeiServices
,
308 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
309 OUT UINTN
*NumberBlockDevices
313 // For Usb devices, this value should be always 1
315 *NumberBlockDevices
= 1;
320 Gets a block device's media information.
322 This function will provide the caller with the specified block device's media
323 information. If the media changes, calling this function will update the media
324 information accordingly.
326 @param[in] PeiServices General-purpose services that are available to every
328 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
329 @param[in] DeviceIndex Specifies the block device to which the function wants
330 to talk. Because the driver that implements Block I/O
331 PPIs will manage multiple block devices, the PPIs that
332 want to talk to a single device must specify the
333 device index that was assigned during the enumeration
334 process. This index is a number from one to
336 @param[out] MediaInfo The media information of the specified block media.
337 The caller is responsible for the ownership of this
340 @retval EFI_SUCCESS Media information about the specified block device
341 was obtained successfully.
342 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
349 IN EFI_PEI_SERVICES
**PeiServices
,
350 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
351 IN UINTN DeviceIndex
,
352 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
355 PEI_BOT_DEVICE
*PeiBotDev
;
358 PeiBotDev
= PEI_BOT_DEVICE_FROM_THIS (This
);
361 // First test unit ready
363 PeiUsbTestUnitReady (
368 Status
= PeiBotDetectMedia (
373 if (EFI_ERROR (Status
)) {
374 return EFI_DEVICE_ERROR
;
380 sizeof (EFI_PEI_BLOCK_IO_MEDIA
)
387 Reads the requested number of blocks from the specified block device.
389 The function reads the requested number of blocks from the device. All the
390 blocks are read, or an error is returned. If there is no media in the device,
391 the function returns EFI_NO_MEDIA.
393 @param[in] PeiServices General-purpose services that are available to
395 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
396 @param[in] DeviceIndex Specifies the block device to which the function wants
397 to talk. Because the driver that implements Block I/O
398 PPIs will manage multiple block devices, the PPIs that
399 want to talk to a single device must specify the device
400 index that was assigned during the enumeration process.
401 This index is a number from one to NumberBlockDevices.
402 @param[in] StartLBA The starting logical block address (LBA) to read from
404 @param[in] BufferSize The size of the Buffer in bytes. This number must be
405 a multiple of the intrinsic block size of the device.
406 @param[out] Buffer A pointer to the destination buffer for the data.
407 The caller is responsible for the ownership of the
410 @retval EFI_SUCCESS The data was read correctly from the device.
411 @retval EFI_DEVICE_ERROR The device reported an error while attempting
412 to perform the read operation.
413 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
414 valid, or the buffer is not properly aligned.
415 @retval EFI_NO_MEDIA There is no media in the device.
416 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
417 the intrinsic block size of the device.
423 IN EFI_PEI_SERVICES
**PeiServices
,
424 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
425 IN UINTN DeviceIndex
,
426 IN EFI_PEI_LBA StartLBA
,
431 PEI_BOT_DEVICE
*PeiBotDev
;
434 UINTN NumberOfBlocks
;
436 Status
= EFI_SUCCESS
;
437 PeiBotDev
= PEI_BOT_DEVICE_FROM_THIS (This
);
442 if (Buffer
== NULL
) {
443 return EFI_INVALID_PARAMETER
;
446 if (BufferSize
== 0) {
450 if (!PeiBotDev
->Media
.MediaPresent
) {
454 BlockSize
= PeiBotDev
->Media
.BlockSize
;
456 if (BufferSize
% BlockSize
!= 0) {
457 Status
= EFI_BAD_BUFFER_SIZE
;
460 if (StartLBA
> PeiBotDev
->Media2
.LastBlock
) {
461 Status
= EFI_INVALID_PARAMETER
;
464 NumberOfBlocks
= BufferSize
/ (PeiBotDev
->Media
.BlockSize
);
466 if (Status
== EFI_SUCCESS
) {
468 Status
= PeiUsbTestUnitReady (
472 if (Status
== EFI_SUCCESS
) {
473 Status
= PeiUsbRead10 (
483 // To generate sense data for DetectMedia use.
485 PeiUsbTestUnitReady (
491 if (EFI_ERROR (Status
)) {
493 // if any error encountered, detect what happened to the media and
494 // update the media info accordingly.
496 Status
= PeiBotDetectMedia (
500 if (Status
!= EFI_SUCCESS
) {
501 return EFI_DEVICE_ERROR
;
504 NumberOfBlocks
= BufferSize
/ PeiBotDev
->Media
.BlockSize
;
506 if (!(PeiBotDev
->Media
.MediaPresent
)) {
510 if (BufferSize
% (PeiBotDev
->Media
.BlockSize
) != 0) {
511 return EFI_BAD_BUFFER_SIZE
;
514 if (StartLBA
> PeiBotDev
->Media2
.LastBlock
) {
515 return EFI_INVALID_PARAMETER
;
518 if ((StartLBA
+ NumberOfBlocks
- 1) > PeiBotDev
->Media2
.LastBlock
) {
519 return EFI_INVALID_PARAMETER
;
522 Status
= PeiUsbRead10 (
536 return EFI_DEVICE_ERROR
;
541 Buffer
= (UINT8
*) Buffer
+ PeiBotDev
->Media
.BlockSize
;
543 if (NumberOfBlocks
== 0) {
547 Status
= PeiUsbRead10 (
560 return EFI_DEVICE_ERROR
;
567 Gets the count of block I/O devices that one specific block driver detects.
569 This function is used for getting the count of block I/O devices that one
570 specific block driver detects. To the PEI ATAPI driver, it returns the number
571 of all the detected ATAPI devices it detects during the enumeration process.
572 To the PEI legacy floppy driver, it returns the number of all the legacy
573 devices it finds during its enumeration process. If no device is detected,
574 then the function will return zero.
576 @param[in] PeiServices General-purpose services that are available
578 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
580 @param[out] NumberBlockDevices The number of block I/O devices discovered.
582 @retval EFI_SUCCESS Operation performed successfully.
587 BotGetNumberOfBlockDevices2 (
588 IN EFI_PEI_SERVICES
**PeiServices
,
589 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
590 OUT UINTN
*NumberBlockDevices
594 // For Usb devices, this value should be always 1
596 *NumberBlockDevices
= 1;
601 Gets a block device's media information.
603 This function will provide the caller with the specified block device's media
604 information. If the media changes, calling this function will update the media
605 information accordingly.
607 @param[in] PeiServices General-purpose services that are available to every
609 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
610 @param[in] DeviceIndex Specifies the block device to which the function wants
611 to talk. Because the driver that implements Block I/O
612 PPIs will manage multiple block devices, the PPIs that
613 want to talk to a single device must specify the
614 device index that was assigned during the enumeration
615 process. This index is a number from one to
617 @param[out] MediaInfo The media information of the specified block media.
618 The caller is responsible for the ownership of this
621 @retval EFI_SUCCESS Media information about the specified block device
622 was obtained successfully.
623 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
630 IN EFI_PEI_SERVICES
**PeiServices
,
631 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
632 IN UINTN DeviceIndex
,
633 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
636 PEI_BOT_DEVICE
*PeiBotDev
;
639 PeiBotDev
= PEI_BOT_DEVICE2_FROM_THIS (This
);
641 Status
= BotGetMediaInfo (
643 &PeiBotDev
->BlkIoPpi
,
648 if (EFI_ERROR (Status
)) {
654 &(PeiBotDev
->Media2
),
655 sizeof (EFI_PEI_BLOCK_IO2_MEDIA
)
662 Reads the requested number of blocks from the specified block device.
664 The function reads the requested number of blocks from the device. All the
665 blocks are read, or an error is returned. If there is no media in the device,
666 the function returns EFI_NO_MEDIA.
668 @param[in] PeiServices General-purpose services that are available to
670 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
671 @param[in] DeviceIndex Specifies the block device to which the function wants
672 to talk. Because the driver that implements Block I/O
673 PPIs will manage multiple block devices, the PPIs that
674 want to talk to a single device must specify the device
675 index that was assigned during the enumeration process.
676 This index is a number from one to NumberBlockDevices.
677 @param[in] StartLBA The starting logical block address (LBA) to read from
679 @param[in] BufferSize The size of the Buffer in bytes. This number must be
680 a multiple of the intrinsic block size of the device.
681 @param[out] Buffer A pointer to the destination buffer for the data.
682 The caller is responsible for the ownership of the
685 @retval EFI_SUCCESS The data was read correctly from the device.
686 @retval EFI_DEVICE_ERROR The device reported an error while attempting
687 to perform the read operation.
688 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
689 valid, or the buffer is not properly aligned.
690 @retval EFI_NO_MEDIA There is no media in the device.
691 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
692 the intrinsic block size of the device.
698 IN EFI_PEI_SERVICES
**PeiServices
,
699 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
700 IN UINTN DeviceIndex
,
701 IN EFI_PEI_LBA StartLBA
,
706 PEI_BOT_DEVICE
*PeiBotDev
;
710 return EFI_INVALID_PARAMETER
;
713 Status
= EFI_SUCCESS
;
714 PeiBotDev
= PEI_BOT_DEVICE2_FROM_THIS (This
);
716 Status
= BotReadBlocks (
718 &PeiBotDev
->BlkIoPpi
,
729 Detect whether the removable media is present and whether it has changed.
731 @param[in] PeiServices General-purpose services that are available to every
733 @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.
735 @retval EFI_SUCCESS The media status is successfully checked.
736 @retval Other Failed to detect media.
741 IN EFI_PEI_SERVICES
**PeiServices
,
742 IN PEI_BOT_DEVICE
*PeiBotDev
746 EFI_STATUS FloppyStatus
;
748 BOOLEAN NeedReadCapacity
;
749 EFI_PHYSICAL_ADDRESS AllocateAddress
;
750 ATAPI_REQUEST_SENSE_DATA
*SensePtr
;
754 // if there is no media present,or media not changed,
755 // the request sense command will detect faster than read capacity command.
756 // read capacity command can be bypassed, thus improve performance.
759 NeedReadCapacity
= TRUE
;
761 Status
= PeiServicesAllocatePages (
766 if (EFI_ERROR (Status
)) {
770 SensePtr
= PeiBotDev
->SensePtr
;
771 ZeroMem (SensePtr
, EFI_PAGE_SIZE
);
773 Status
= PeiUsbRequestSense (
780 if (Status
== EFI_SUCCESS
) {
784 if (IsNoMedia (SensePtr
, SenseCounts
)) {
785 NeedReadCapacity
= FALSE
;
786 PeiBotDev
->Media
.MediaPresent
= FALSE
;
787 PeiBotDev
->Media
.LastBlock
= 0;
788 PeiBotDev
->Media2
.MediaPresent
= FALSE
;
789 PeiBotDev
->Media2
.LastBlock
= 0;
794 if (IsMediaChange (SensePtr
, SenseCounts
)) {
795 PeiBotDev
->Media
.MediaPresent
= TRUE
;
796 PeiBotDev
->Media2
.MediaPresent
= TRUE
;
801 if (IsMediaError (SensePtr
, SenseCounts
)) {
803 // if media error encountered, make it look like no media present.
805 PeiBotDev
->Media
.MediaPresent
= FALSE
;
806 PeiBotDev
->Media
.LastBlock
= 0;
807 PeiBotDev
->Media2
.MediaPresent
= FALSE
;
808 PeiBotDev
->Media2
.LastBlock
= 0;
815 if (NeedReadCapacity
) {
817 // Retry at most 4 times to detect media info
819 for (Retry
= 0; Retry
< 4; Retry
++) {
820 switch (PeiBotDev
->DeviceType
) {
822 Status
= PeiUsbReadCapacity (
829 Status
= PeiUsbReadFormattedCapacity (
833 if (EFI_ERROR(Status
)||
834 !PeiBotDev
->Media
.MediaPresent
) {
836 // retry the ReadCapacity command
838 PeiBotDev
->DeviceType
= USBFLOPPY
;
839 Status
= EFI_DEVICE_ERROR
;
844 Status
= PeiUsbReadCapacity (
848 if (EFI_ERROR (Status
)) {
850 // retry the ReadFormatCapacity command
852 PeiBotDev
->DeviceType
= USBFLOPPY2
;
857 return EFI_INVALID_PARAMETER
;
861 ZeroMem (SensePtr
, EFI_PAGE_SIZE
);
863 if (Status
== EFI_SUCCESS
) {
867 FloppyStatus
= PeiUsbRequestSense (
875 // If Request Sense data failed,retry.
877 if (EFI_ERROR (FloppyStatus
)) {
883 if (IsNoMedia (SensePtr
, SenseCounts
)) {
884 PeiBotDev
->Media
.MediaPresent
= FALSE
;
885 PeiBotDev
->Media
.LastBlock
= 0;
886 PeiBotDev
->Media2
.MediaPresent
= FALSE
;
887 PeiBotDev
->Media2
.LastBlock
= 0;
891 if (IsMediaError (SensePtr
, SenseCounts
)) {
893 // if media error encountered, make it look like no media present.
895 PeiBotDev
->Media
.MediaPresent
= FALSE
;
896 PeiBotDev
->Media
.LastBlock
= 0;
897 PeiBotDev
->Media2
.MediaPresent
= FALSE
;
898 PeiBotDev
->Media2
.LastBlock
= 0;
905 // tell whether the readcapacity process is successful or not
906 // ("Status" variable record the latest status returned
909 if (Status
!= EFI_SUCCESS
) {
910 return EFI_DEVICE_ERROR
;