/** The function waits for the boot manager timeout expires or hotkey is pressed. It calls PlatformBootManagerWaitCallback each second. @param HotkeyTriggered Input hotkey event. **/ VOID BdsWait ( IN EFI_EVENT HotkeyTriggered ) { EFI_STATUS Status; UINT16 TimeoutRemain; DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n")); TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut); while (TimeoutRemain != 0) { DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain)); PlatformBootManagerWaitCallback (TimeoutRemain); BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered // Can be removed after all keyboard drivers invoke callback in timer callback. if (HotkeyTriggered != NULL) { Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1)); if (!EFI_ERROR (Status)) { break; } } else { gBS->Stall (1000000); } // // 0xffff means waiting forever // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop // if (TimeoutRemain != 0xffff) { TimeoutRemain--; } } DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n")); }
/** Execute the USB mass storage bootability commands with retrial. This function executes USB mass storage bootability commands. 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 @param DataDir The direction of data transfer @param Data The buffer to hold the data @param DataLen The length of expected data @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 Others Command execution failed after retrial. **/ EFI_STATUS UsbBootExecCmdWithRetry ( IN USB_MASS_DEVICE *UsbMass, IN VOID *Cmd, IN UINT8 CmdLen, IN EFI_USB_DATA_DIRECTION DataDir, IN VOID *Data, IN UINT32 DataLen, IN UINT32 Timeout ) { 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 = 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, CmdLen, DataDir, Data, DataLen, Timeout ); if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) { break; } // // 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) { 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; }
/** Discovery SCSI Device @param ScsiIoDevice The pointer of SCSI_IO_DEV @retval TRUE Find SCSI Device and verify it. @retval FALSE Unable to find SCSI Device. **/ BOOLEAN DiscoverScsiDevice ( IN OUT SCSI_IO_DEV *ScsiIoDevice ) { EFI_STATUS Status; UINT32 InquiryDataLength; UINT8 SenseDataLength; UINT8 HostAdapterStatus; UINT8 TargetStatus; EFI_SCSI_INQUIRY_DATA *InquiryData; UINT8 MaxRetry; UINT8 Index; BOOLEAN ScsiDeviceFound; HostAdapterStatus = 0; TargetStatus = 0; InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA)); if (InquiryData == NULL) { ScsiDeviceFound = FALSE; goto Done; } // // Using Inquiry command to scan for the device // InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA); SenseDataLength = 0; ZeroMem (InquiryData, InquiryDataLength); MaxRetry = 2; for (Index = 0; Index < MaxRetry; Index++) { Status = ScsiInquiryCommand ( &ScsiIoDevice->ScsiIo, EFI_TIMER_PERIOD_SECONDS (1), NULL, &SenseDataLength, &HostAdapterStatus, &TargetStatus, (VOID *) InquiryData, &InquiryDataLength, FALSE ); if (!EFI_ERROR (Status)) { break; } else if ((Status == EFI_BAD_BUFFER_SIZE) || (Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) { ScsiDeviceFound = FALSE; goto Done; } } if (Index == MaxRetry) { ScsiDeviceFound = FALSE; goto Done; } // // Retrieved inquiry data successfully // if ((InquiryData->Peripheral_Qualifier != 0) && (InquiryData->Peripheral_Qualifier != 3)) { ScsiDeviceFound = FALSE; goto Done; } if (InquiryData->Peripheral_Qualifier == 3) { if (InquiryData->Peripheral_Type != 0x1f) { ScsiDeviceFound = FALSE; goto Done; } } if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) { ScsiDeviceFound = FALSE; goto Done; } // // valid device type and peripheral qualifier combination. // ScsiIoDevice->ScsiDeviceType = InquiryData->Peripheral_Type; ScsiIoDevice->RemovableDevice = InquiryData->Rmb; if (InquiryData->Version == 0) { ScsiIoDevice->ScsiVersion = 0; } else { // // ANSI-approved version // ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07); } ScsiDeviceFound = TRUE; Done: FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA)); return ScsiDeviceFound; }