1 /** @file
2 
3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
4 
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "UsbBotPeim.h"
10 #include "BotPeim.h"
11 
12 //
13 // Global function
14 //
15 EFI_PEI_NOTIFY_DESCRIPTOR        mNotifyList = {
16   EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
17   &gPeiUsbIoPpiGuid,
18   NotifyOnUsbIoPpi
19 };
20 
21 EFI_PEI_RECOVERY_BLOCK_IO_PPI    mRecoveryBlkIoPpi = {
22   BotGetNumberOfBlockDevices,
23   BotGetMediaInfo,
24   BotReadBlocks
25 };
26 
27 EFI_PEI_RECOVERY_BLOCK_IO2_PPI   mRecoveryBlkIo2Ppi = {
28   EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
29   BotGetNumberOfBlockDevices2,
30   BotGetMediaInfo2,
31   BotReadBlocks2
32 };
33 
34 EFI_PEI_PPI_DESCRIPTOR           mPpiList[2] = {
35   {
36     EFI_PEI_PPI_DESCRIPTOR_PPI,
37     &gEfiPeiVirtualBlockIoPpiGuid,
38     NULL
39   },
40   {
41     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
42     &gEfiPeiVirtualBlockIo2PpiGuid,
43     NULL
44   }
45 };
46 
47 /**
48   Detect whether the removable media is present and whether it has changed.
49 
50   @param[in]  PeiServices   General-purpose services that are available to every
51                             PEIM.
52   @param[in]  PeiBotDev     Indicates the PEI_BOT_DEVICE instance.
53 
54   @retval EFI_SUCCESS       The media status is successfully checked.
55   @retval Other             Failed to detect media.
56 
57 **/
58 EFI_STATUS
59 PeiBotDetectMedia (
60   IN  EFI_PEI_SERVICES                          **PeiServices,
61   IN  PEI_BOT_DEVICE                            *PeiBotDev
62   );
63 
64 /**
65   Initializes the Usb Bot.
66 
67   @param  FileHandle  Handle of the file being invoked.
68   @param  PeiServices Describes the list of possible PEI Services.
69 
70   @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
71   @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
72 
73 **/
74 EFI_STATUS
75 EFIAPI
PeimInitializeUsbBot(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)76 PeimInitializeUsbBot (
77   IN EFI_PEI_FILE_HANDLE       FileHandle,
78   IN CONST EFI_PEI_SERVICES    **PeiServices
79   )
80 {
81   EFI_STATUS                  Status;
82   UINTN                       UsbIoPpiInstance;
83   EFI_PEI_PPI_DESCRIPTOR      *TempPpiDescriptor;
84   PEI_USB_IO_PPI              *UsbIoPpi;
85 
86   //
87   // Shadow this PEIM to run from memory
88   //
89   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
90     return EFI_SUCCESS;
91   }
92 
93   //
94   // locate all usb io PPIs
95   //
96   for (UsbIoPpiInstance = 0; UsbIoPpiInstance < PEI_FAT_MAX_USB_IO_PPI; UsbIoPpiInstance++) {
97 
98     Status = PeiServicesLocatePpi (
99                               &gPeiUsbIoPpiGuid,
100                               UsbIoPpiInstance,
101                               &TempPpiDescriptor,
102                               (VOID **) &UsbIoPpi
103                               );
104     if (EFI_ERROR (Status)) {
105       break;
106     }
107   }
108   //
109   // Register a notify function
110   //
111   return PeiServicesNotifyPpi (&mNotifyList);
112 }
113 
114 /**
115   UsbIo installation notification function.
116 
117   This function finds out all the current USB IO PPIs in the system and add them
118   into private data.
119 
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.
123 
124   @retval EFI_SUCCESS      The function completes successfully.
125 
126 **/
127 EFI_STATUS
128 EFIAPI
NotifyOnUsbIoPpi(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDesc,IN VOID * InvokePpi)129 NotifyOnUsbIoPpi (
130   IN  EFI_PEI_SERVICES                              **PeiServices,
131   IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,
132   IN  VOID                                          *InvokePpi
133   )
134 {
135   PEI_USB_IO_PPI  *UsbIoPpi;
136 
137   UsbIoPpi = (PEI_USB_IO_PPI *) InvokePpi;
138 
139   InitUsbBot (PeiServices, UsbIoPpi);
140 
141   return EFI_SUCCESS;
142 }
143 
144 /**
145   Initialize the usb bot device.
146 
147   @param[in]  PeiServices   General-purpose services that are available to every
148                             PEIM.
149   @param[in]  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
150 
151   @retval EFI_SUCCESS       The usb bot device is initialized successfully.
152   @retval Other             Failed to initialize media.
153 
154 **/
155 EFI_STATUS
InitUsbBot(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi)156 InitUsbBot (
157   IN  EFI_PEI_SERVICES                          **PeiServices,
158   IN  PEI_USB_IO_PPI                            *UsbIoPpi
159   )
160 {
161   PEI_BOT_DEVICE                *PeiBotDevice;
162   EFI_STATUS                    Status;
163   EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDesc;
164   UINTN                         MemPages;
165   EFI_PHYSICAL_ADDRESS          AllocateAddress;
166   EFI_USB_ENDPOINT_DESCRIPTOR   *EndpointDesc;
167   UINT8                         Index;
168 
169   //
170   // Check its interface
171   //
172   Status = UsbIoPpi->UsbGetInterfaceDescriptor (
173                       PeiServices,
174                       UsbIoPpi,
175                       &InterfaceDesc
176                       );
177   if (EFI_ERROR (Status)) {
178     return Status;
179   }
180   //
181   // Check if it is the BOT device we support
182   //
183   if ((InterfaceDesc->InterfaceClass != 0x08) || (InterfaceDesc->InterfaceProtocol != 0x50)) {
184 
185     return EFI_NOT_FOUND;
186   }
187 
188   MemPages = sizeof (PEI_BOT_DEVICE) / EFI_PAGE_SIZE + 1;
189   Status = PeiServicesAllocatePages (
190              EfiBootServicesCode,
191              MemPages,
192              &AllocateAddress
193              );
194   if (EFI_ERROR (Status)) {
195     return Status;
196   }
197 
198   PeiBotDevice                  = (PEI_BOT_DEVICE *) ((UINTN) AllocateAddress);
199 
200   PeiBotDevice->Signature       = PEI_BOT_DEVICE_SIGNATURE;
201   PeiBotDevice->UsbIoPpi        = UsbIoPpi;
202   PeiBotDevice->AllocateAddress = (UINTN) AllocateAddress;
203   PeiBotDevice->BotInterface    = InterfaceDesc;
204 
205   //
206   // Default value
207   //
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;
214 
215   //
216   // Check its Bulk-in/Bulk-out endpoint
217   //
218   for (Index = 0; Index < 2; Index++) {
219     Status = UsbIoPpi->UsbGetEndpointDescriptor (
220                         PeiServices,
221                         UsbIoPpi,
222                         Index,
223                         &EndpointDesc
224                         );
225 
226     if (EFI_ERROR (Status)) {
227       return Status;
228     }
229 
230     if ((EndpointDesc->EndpointAddress & 0x80) != 0) {
231       PeiBotDevice->BulkInEndpoint = EndpointDesc;
232     } else {
233       PeiBotDevice->BulkOutEndpoint = EndpointDesc;
234     }
235   }
236 
237   CopyMem (
238     &(PeiBotDevice->BlkIoPpi),
239     &mRecoveryBlkIoPpi,
240     sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI)
241     );
242   CopyMem (
243     &(PeiBotDevice->BlkIo2Ppi),
244     &mRecoveryBlkIo2Ppi,
245     sizeof (EFI_PEI_RECOVERY_BLOCK_IO2_PPI)
246     );
247   CopyMem (
248     &(PeiBotDevice->BlkIoPpiList),
249     &mPpiList[0],
250     sizeof (EFI_PEI_PPI_DESCRIPTOR)
251     );
252   CopyMem (
253     &(PeiBotDevice->BlkIo2PpiList),
254     &mPpiList[1],
255     sizeof (EFI_PEI_PPI_DESCRIPTOR)
256     );
257   PeiBotDevice->BlkIoPpiList.Ppi  = &PeiBotDevice->BlkIoPpi;
258   PeiBotDevice->BlkIo2PpiList.Ppi = &PeiBotDevice->BlkIo2Ppi;
259 
260   Status                          = PeiUsbInquiry (PeiServices, PeiBotDevice);
261   if (EFI_ERROR (Status)) {
262     return Status;
263   }
264 
265   Status = PeiServicesAllocatePages (
266              EfiBootServicesCode,
267              1,
268              &AllocateAddress
269              );
270   if (EFI_ERROR (Status)) {
271     return Status;
272   }
273 
274   PeiBotDevice->SensePtr = (ATAPI_REQUEST_SENSE_DATA *) ((UINTN) AllocateAddress);
275 
276   Status = PeiServicesInstallPpi (&PeiBotDevice->BlkIoPpiList);
277 
278   if (EFI_ERROR (Status)) {
279     return Status;
280   }
281 
282   return EFI_SUCCESS;
283 }
284 
285 /**
286   Gets the count of block I/O devices that one specific block driver detects.
287 
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.
294 
295   @param[in]  PeiServices          General-purpose services that are available
296                                    to every PEIM.
297   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
298                                    instance.
299   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
300 
301   @retval     EFI_SUCCESS          Operation performed successfully.
302 
303 **/
304 EFI_STATUS
305 EFIAPI
BotGetNumberOfBlockDevices(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,OUT UINTN * NumberBlockDevices)306 BotGetNumberOfBlockDevices (
307   IN  EFI_PEI_SERVICES                         **PeiServices,
308   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI            *This,
309   OUT UINTN                                    *NumberBlockDevices
310   )
311 {
312   //
313   // For Usb devices, this value should be always 1
314   //
315   *NumberBlockDevices = 1;
316   return EFI_SUCCESS;
317 }
318 
319 /**
320   Gets a block device's media information.
321 
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.
325 
326   @param[in]  PeiServices   General-purpose services that are available to every
327                             PEIM
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
335                             NumberBlockDevices.
336   @param[out] MediaInfo     The media information of the specified block media.
337                             The caller is responsible for the ownership of this
338                             data structure.
339 
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
343                              error.
344 
345 **/
346 EFI_STATUS
347 EFIAPI
BotGetMediaInfo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO_MEDIA * MediaInfo)348 BotGetMediaInfo (
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
353   )
354 {
355   PEI_BOT_DEVICE  *PeiBotDev;
356   EFI_STATUS      Status;
357 
358   PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);
359 
360   //
361   // First test unit ready
362   //
363   PeiUsbTestUnitReady (
364     PeiServices,
365     PeiBotDev
366     );
367 
368   Status = PeiBotDetectMedia (
369             PeiServices,
370             PeiBotDev
371             );
372 
373   if (EFI_ERROR (Status)) {
374     return EFI_DEVICE_ERROR;
375   }
376 
377   CopyMem (
378     MediaInfo,
379     &(PeiBotDev->Media),
380     sizeof (EFI_PEI_BLOCK_IO_MEDIA)
381     );
382 
383   return EFI_SUCCESS;
384 }
385 
386 /**
387   Reads the requested number of blocks from the specified block device.
388 
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.
392 
393   @param[in]  PeiServices   General-purpose services that are available to
394                             every PEIM.
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
403                             on the device
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
408                             buffer.
409 
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.
418 
419 **/
420 EFI_STATUS
421 EFIAPI
BotReadBlocks(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)422 BotReadBlocks (
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,
427   IN  UINTN                                     BufferSize,
428   OUT VOID                                      *Buffer
429   )
430 {
431   PEI_BOT_DEVICE  *PeiBotDev;
432   EFI_STATUS      Status;
433   UINTN           BlockSize;
434   UINTN           NumberOfBlocks;
435 
436   Status    = EFI_SUCCESS;
437   PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);
438 
439   //
440   // Check parameters
441   //
442   if (Buffer == NULL) {
443     return EFI_INVALID_PARAMETER;
444   }
445 
446   if (BufferSize == 0) {
447     return EFI_SUCCESS;
448   }
449 
450   if (!PeiBotDev->Media.MediaPresent) {
451     return EFI_NO_MEDIA;
452   }
453 
454   BlockSize = PeiBotDev->Media.BlockSize;
455 
456   if (BufferSize % BlockSize != 0) {
457     Status = EFI_BAD_BUFFER_SIZE;
458   }
459 
460   if (StartLBA > PeiBotDev->Media2.LastBlock) {
461     Status = EFI_INVALID_PARAMETER;
462   }
463 
464   NumberOfBlocks = BufferSize / (PeiBotDev->Media.BlockSize);
465 
466   if (Status == EFI_SUCCESS) {
467 
468     Status = PeiUsbTestUnitReady (
469               PeiServices,
470               PeiBotDev
471               );
472     if (Status == EFI_SUCCESS) {
473       Status = PeiUsbRead10 (
474                 PeiServices,
475                 PeiBotDev,
476                 Buffer,
477                 StartLBA,
478                 1
479                 );
480     }
481   } else {
482     //
483     // To generate sense data for DetectMedia use.
484     //
485     PeiUsbTestUnitReady (
486       PeiServices,
487       PeiBotDev
488       );
489   }
490 
491   if (EFI_ERROR (Status)) {
492     //
493     // if any error encountered, detect what happened to the media and
494     // update the media info accordingly.
495     //
496     Status = PeiBotDetectMedia (
497               PeiServices,
498               PeiBotDev
499               );
500     if (Status != EFI_SUCCESS) {
501       return EFI_DEVICE_ERROR;
502     }
503 
504     NumberOfBlocks = BufferSize / PeiBotDev->Media.BlockSize;
505 
506     if (!(PeiBotDev->Media.MediaPresent)) {
507       return EFI_NO_MEDIA;
508     }
509 
510     if (BufferSize % (PeiBotDev->Media.BlockSize) != 0) {
511       return EFI_BAD_BUFFER_SIZE;
512     }
513 
514     if (StartLBA > PeiBotDev->Media2.LastBlock) {
515       return EFI_INVALID_PARAMETER;
516     }
517 
518     if ((StartLBA + NumberOfBlocks - 1) > PeiBotDev->Media2.LastBlock) {
519       return EFI_INVALID_PARAMETER;
520     }
521 
522     Status = PeiUsbRead10 (
523               PeiServices,
524               PeiBotDev,
525               Buffer,
526               StartLBA,
527               NumberOfBlocks
528               );
529 
530     switch (Status) {
531 
532     case EFI_SUCCESS:
533       return EFI_SUCCESS;
534 
535     default:
536       return EFI_DEVICE_ERROR;
537     }
538   } else {
539     StartLBA += 1;
540     NumberOfBlocks -= 1;
541     Buffer = (UINT8 *) Buffer + PeiBotDev->Media.BlockSize;
542 
543     if (NumberOfBlocks == 0) {
544       return EFI_SUCCESS;
545     }
546 
547     Status = PeiUsbRead10 (
548               PeiServices,
549               PeiBotDev,
550               Buffer,
551               StartLBA,
552               NumberOfBlocks
553               );
554     switch (Status) {
555 
556     case EFI_SUCCESS:
557       return EFI_SUCCESS;
558 
559     default:
560       return EFI_DEVICE_ERROR;
561 
562     }
563   }
564 }
565 
566 /**
567   Gets the count of block I/O devices that one specific block driver detects.
568 
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.
575 
576   @param[in]  PeiServices          General-purpose services that are available
577                                    to every PEIM.
578   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
579                                    instance.
580   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
581 
582   @retval     EFI_SUCCESS          Operation performed successfully.
583 
584 **/
585 EFI_STATUS
586 EFIAPI
BotGetNumberOfBlockDevices2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,OUT UINTN * NumberBlockDevices)587 BotGetNumberOfBlockDevices2 (
588   IN  EFI_PEI_SERVICES                         **PeiServices,
589   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI           *This,
590   OUT UINTN                                    *NumberBlockDevices
591   )
592 {
593   //
594   // For Usb devices, this value should be always 1
595   //
596   *NumberBlockDevices = 1;
597   return EFI_SUCCESS;
598 }
599 
600 /**
601   Gets a block device's media information.
602 
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.
606 
607   @param[in]  PeiServices   General-purpose services that are available to every
608                             PEIM
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
616                             NumberBlockDevices.
617   @param[out] MediaInfo     The media information of the specified block media.
618                             The caller is responsible for the ownership of this
619                             data structure.
620 
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
624                              error.
625 
626 **/
627 EFI_STATUS
628 EFIAPI
BotGetMediaInfo2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO2_MEDIA * MediaInfo)629 BotGetMediaInfo2 (
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
634   )
635 {
636   PEI_BOT_DEVICE  *PeiBotDev;
637   EFI_STATUS      Status;
638 
639   PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This);
640 
641   Status = BotGetMediaInfo (
642              PeiServices,
643              &PeiBotDev->BlkIoPpi,
644              DeviceIndex,
645              &PeiBotDev->Media
646              );
647 
648   if (EFI_ERROR (Status)) {
649     return Status;
650   }
651 
652   CopyMem (
653     MediaInfo,
654     &(PeiBotDev->Media2),
655     sizeof (EFI_PEI_BLOCK_IO2_MEDIA)
656     );
657 
658   return EFI_SUCCESS;
659 }
660 
661 /**
662   Reads the requested number of blocks from the specified block device.
663 
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.
667 
668   @param[in]  PeiServices   General-purpose services that are available to
669                             every PEIM.
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
678                             on the device
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
683                             buffer.
684 
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.
693 
694 **/
695 EFI_STATUS
696 EFIAPI
BotReadBlocks2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)697 BotReadBlocks2 (
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,
702   IN  UINTN                                     BufferSize,
703   OUT VOID                                      *Buffer
704   )
705 {
706   PEI_BOT_DEVICE  *PeiBotDev;
707   EFI_STATUS      Status;
708 
709   if (This == NULL) {
710     return EFI_INVALID_PARAMETER;
711   }
712 
713   Status    = EFI_SUCCESS;
714   PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This);
715 
716   Status = BotReadBlocks (
717              PeiServices,
718              &PeiBotDev->BlkIoPpi,
719              DeviceIndex,
720              StartLBA,
721              BufferSize,
722              Buffer
723              );
724 
725   return Status;
726 }
727 
728 /**
729   Detect whether the removable media is present and whether it has changed.
730 
731   @param[in]  PeiServices   General-purpose services that are available to every
732                             PEIM.
733   @param[in]  PeiBotDev     Indicates the PEI_BOT_DEVICE instance.
734 
735   @retval EFI_SUCCESS       The media status is successfully checked.
736   @retval Other             Failed to detect media.
737 
738 **/
739 EFI_STATUS
PeiBotDetectMedia(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_BOT_DEVICE * PeiBotDev)740 PeiBotDetectMedia (
741   IN  EFI_PEI_SERVICES        **PeiServices,
742   IN  PEI_BOT_DEVICE          *PeiBotDev
743   )
744 {
745   EFI_STATUS                  Status;
746   EFI_STATUS                  FloppyStatus;
747   UINTN                       SenseCounts;
748   BOOLEAN                     NeedReadCapacity;
749   EFI_PHYSICAL_ADDRESS        AllocateAddress;
750   ATAPI_REQUEST_SENSE_DATA    *SensePtr;
751   UINTN                       Retry;
752 
753   //
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.
757   //
758   SenseCounts       = 0;
759   NeedReadCapacity  = TRUE;
760 
761   Status = PeiServicesAllocatePages (
762              EfiBootServicesCode,
763              1,
764              &AllocateAddress
765              );
766   if (EFI_ERROR (Status)) {
767     return Status;
768   }
769 
770   SensePtr = PeiBotDev->SensePtr;
771   ZeroMem (SensePtr, EFI_PAGE_SIZE);
772 
773   Status = PeiUsbRequestSense (
774             PeiServices,
775             PeiBotDev,
776             &SenseCounts,
777             (UINT8 *) SensePtr
778             );
779 
780   if (Status == EFI_SUCCESS) {
781     //
782     // No Media
783     //
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;
790     } else {
791       //
792       // Media Changed
793       //
794       if (IsMediaChange (SensePtr, SenseCounts)) {
795         PeiBotDev->Media.MediaPresent  = TRUE;
796         PeiBotDev->Media2.MediaPresent = TRUE;
797       }
798       //
799       // Media Error
800       //
801       if (IsMediaError (SensePtr, SenseCounts)) {
802         //
803         // if media error encountered, make it look like no media present.
804         //
805         PeiBotDev->Media.MediaPresent = FALSE;
806         PeiBotDev->Media.LastBlock    = 0;
807         PeiBotDev->Media2.MediaPresent = FALSE;
808         PeiBotDev->Media2.LastBlock    = 0;
809       }
810 
811     }
812 
813   }
814 
815   if (NeedReadCapacity) {
816     //
817     // Retry at most 4 times to detect media info
818     //
819     for (Retry = 0; Retry < 4; Retry++) {
820       switch (PeiBotDev->DeviceType) {
821       case USBCDROM:
822         Status = PeiUsbReadCapacity (
823                   PeiServices,
824                   PeiBotDev
825                   );
826         break;
827 
828       case USBFLOPPY2:
829         Status = PeiUsbReadFormattedCapacity (
830                   PeiServices,
831                   PeiBotDev
832                   );
833           if (EFI_ERROR(Status)||
834               !PeiBotDev->Media.MediaPresent) {
835           //
836           // retry the ReadCapacity command
837           //
838           PeiBotDev->DeviceType = USBFLOPPY;
839           Status = EFI_DEVICE_ERROR;
840         }
841         break;
842 
843       case USBFLOPPY:
844         Status = PeiUsbReadCapacity (
845                   PeiServices,
846                   PeiBotDev
847                   );
848         if (EFI_ERROR (Status)) {
849           //
850           // retry the ReadFormatCapacity command
851           //
852           PeiBotDev->DeviceType = USBFLOPPY2;
853         }
854         break;
855 
856       default:
857         return EFI_INVALID_PARAMETER;
858       }
859 
860       SenseCounts = 0;
861       ZeroMem (SensePtr, EFI_PAGE_SIZE);
862 
863       if (Status == EFI_SUCCESS) {
864         break;
865       }
866 
867       FloppyStatus = PeiUsbRequestSense (
868                       PeiServices,
869                       PeiBotDev,
870                       &SenseCounts,
871                       (UINT8 *) SensePtr
872                       );
873 
874       //
875       // If Request Sense data failed,retry.
876       //
877       if (EFI_ERROR (FloppyStatus)) {
878         continue;
879       }
880       //
881       // No Media
882       //
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;
888         break;
889       }
890 
891       if (IsMediaError (SensePtr, SenseCounts)) {
892         //
893         // if media error encountered, make it look like no media present.
894         //
895         PeiBotDev->Media.MediaPresent = FALSE;
896         PeiBotDev->Media.LastBlock    = 0;
897         PeiBotDev->Media2.MediaPresent = FALSE;
898         PeiBotDev->Media2.LastBlock    = 0;
899         break;
900       }
901     }
902     //
903     // ENDFOR
904     //
905     // tell whether the readcapacity process is successful or not
906     // ("Status" variable record the latest status returned
907     // by ReadCapacity )
908     //
909     if (Status != EFI_SUCCESS) {
910       return EFI_DEVICE_ERROR;
911     }
912   }
913 
914   return EFI_SUCCESS;
915 }
916