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