1/** @file
2
3Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
4
5This program and the accompanying materials
6are licensed and made available under the terms and conditions
7of the BSD License which accompanies this distribution.  The
8full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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//
22EFI_PEI_NOTIFY_DESCRIPTOR        mNotifyList = {
23  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
24  &gPeiUsbIoPpiGuid,
25  NotifyOnUsbIoPpi
26};
27
28EFI_PEI_RECOVERY_BLOCK_IO_PPI    mRecoveryBlkIoPpi = {
29  BotGetNumberOfBlockDevices,
30  BotGetMediaInfo,
31  BotReadBlocks
32};
33
34EFI_PEI_RECOVERY_BLOCK_IO2_PPI   mRecoveryBlkIo2Ppi = {
35  EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
36  BotGetNumberOfBlockDevices2,
37  BotGetMediaInfo2,
38  BotReadBlocks2
39};
40
41EFI_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**/
65EFI_STATUS
66PeiBotDetectMedia (
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**/
81EFI_STATUS
82EFIAPI
83PeimInitializeUsbBot (
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**/
134EFI_STATUS
135EFIAPI
136NotifyOnUsbIoPpi (
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**/
162EFI_STATUS
163InitUsbBot (
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**/
311EFI_STATUS
312EFIAPI
313BotGetNumberOfBlockDevices (
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**/
353EFI_STATUS
354EFIAPI
355BotGetMediaInfo (
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**/
427EFI_STATUS
428EFIAPI
429BotReadBlocks (
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**/
592EFI_STATUS
593EFIAPI
594BotGetNumberOfBlockDevices2 (
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**/
634EFI_STATUS
635EFIAPI
636BotGetMediaInfo2 (
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**/
702EFI_STATUS
703EFIAPI
704BotReadBlocks2 (
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**/
746EFI_STATUS
747PeiBotDetectMedia (
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