1 /** @file
2   SCSI disk driver that layers on every SCSI IO protocol in the system.
3 
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 
10 #include "ScsiDisk.h"
11 
12 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
13   ScsiDiskDriverBindingSupported,
14   ScsiDiskDriverBindingStart,
15   ScsiDiskDriverBindingStop,
16   0xa,
17   NULL,
18   NULL
19 };
20 
21 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
22   EFI_DISK_INFO_SCSI_INTERFACE_GUID,
23   ScsiDiskInfoInquiry,
24   ScsiDiskInfoIdentify,
25   ScsiDiskInfoSenseData,
26   ScsiDiskInfoWhichIde
27 };
28 
29 /**
30   Allocates an aligned buffer for SCSI disk.
31 
32   This function allocates an aligned buffer for the SCSI disk to perform
33   SCSI IO operations. The alignment requirement is from SCSI IO interface.
34 
35   @param  ScsiDiskDevice    The SCSI disk involved for the operation.
36   @param  BufferSize        The request buffer size.
37 
38   @return A pointer to the aligned buffer or NULL if the allocation fails.
39 
40 **/
41 VOID *
AllocateAlignedBuffer(IN SCSI_DISK_DEV * ScsiDiskDevice,IN UINTN BufferSize)42 AllocateAlignedBuffer (
43   IN SCSI_DISK_DEV            *ScsiDiskDevice,
44   IN UINTN                    BufferSize
45   )
46 {
47   return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);
48 }
49 
50 /**
51   Frees an aligned buffer for SCSI disk.
52 
53   This function frees an aligned buffer for the SCSI disk to perform
54   SCSI IO operations.
55 
56   @param  Buffer            The aligned buffer to be freed.
57   @param  BufferSize        The request buffer size.
58 
59 **/
60 VOID
FreeAlignedBuffer(IN VOID * Buffer,IN UINTN BufferSize)61 FreeAlignedBuffer (
62   IN VOID                     *Buffer,
63   IN UINTN                    BufferSize
64   )
65 {
66   if (Buffer != NULL) {
67     FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
68   }
69 }
70 
71 /**
72   The user Entry Point for module ScsiDisk.
73 
74   The user code starts with this function.
75 
76   @param  ImageHandle    The firmware allocated handle for the EFI image.
77   @param  SystemTable    A pointer to the EFI System Table.
78 
79   @retval EFI_SUCCESS       The entry point is executed successfully.
80   @retval other             Some error occurs when executing this entry point.
81 
82 **/
83 EFI_STATUS
84 EFIAPI
InitializeScsiDisk(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)85 InitializeScsiDisk(
86   IN EFI_HANDLE           ImageHandle,
87   IN EFI_SYSTEM_TABLE     *SystemTable
88   )
89 {
90   EFI_STATUS              Status;
91 
92   //
93   // Install driver model protocol(s).
94   //
95   Status = EfiLibInstallDriverBindingComponentName2 (
96              ImageHandle,
97              SystemTable,
98              &gScsiDiskDriverBinding,
99              ImageHandle,
100              &gScsiDiskComponentName,
101              &gScsiDiskComponentName2
102              );
103   ASSERT_EFI_ERROR (Status);
104 
105 
106   return Status;
107 }
108 
109 /**
110   Test to see if this driver supports ControllerHandle.
111 
112   This service is called by the EFI boot service ConnectController(). In order
113   to make drivers as small as possible, there are a few calling restrictions for
114   this service. ConnectController() must follow these calling restrictions.
115   If any other agent wishes to call Supported() it must also follow these
116   calling restrictions.
117 
118   @param  This                Protocol instance pointer.
119   @param  ControllerHandle    Handle of device to test
120   @param  RemainingDevicePath Optional parameter use to pick a specific child
121                               device to start.
122 
123   @retval EFI_SUCCESS         This driver supports this device
124   @retval EFI_ALREADY_STARTED This driver is already running on this device
125   @retval other               This driver does not support this device
126 
127 **/
128 EFI_STATUS
129 EFIAPI
ScsiDiskDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)130 ScsiDiskDriverBindingSupported (
131   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
132   IN EFI_HANDLE                   Controller,
133   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
134   )
135 {
136   EFI_STATUS            Status;
137   EFI_SCSI_IO_PROTOCOL  *ScsiIo;
138   UINT8                 DeviceType;
139 
140   Status = gBS->OpenProtocol (
141                   Controller,
142                   &gEfiScsiIoProtocolGuid,
143                   (VOID **) &ScsiIo,
144                   This->DriverBindingHandle,
145                   Controller,
146                   EFI_OPEN_PROTOCOL_BY_DRIVER
147                   );
148   if (EFI_ERROR (Status)) {
149     return Status;
150   }
151 
152   Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
153   if (!EFI_ERROR (Status)) {
154     if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {
155       Status = EFI_SUCCESS;
156     } else {
157       Status = EFI_UNSUPPORTED;
158     }
159   }
160 
161   gBS->CloseProtocol (
162          Controller,
163          &gEfiScsiIoProtocolGuid,
164          This->DriverBindingHandle,
165          Controller
166          );
167   return Status;
168 }
169 
170 
171 /**
172   Start this driver on ControllerHandle.
173 
174   This service is called by the EFI boot service ConnectController(). In order
175   to make drivers as small as possible, there are a few calling restrictions for
176   this service. ConnectController() must follow these calling restrictions. If
177   any other agent wishes to call Start() it must also follow these calling
178   restrictions.
179 
180   @param  This                 Protocol instance pointer.
181   @param  ControllerHandle     Handle of device to bind driver to
182   @param  RemainingDevicePath  Optional parameter use to pick a specific child
183                                device to start.
184 
185   @retval EFI_SUCCESS          This driver is added to ControllerHandle
186   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
187   @retval other                This driver does not support this device
188 
189 **/
190 EFI_STATUS
191 EFIAPI
ScsiDiskDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)192 ScsiDiskDriverBindingStart (
193   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
194   IN EFI_HANDLE                   Controller,
195   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
196   )
197 {
198   EFI_STATUS            Status;
199   EFI_SCSI_IO_PROTOCOL  *ScsiIo;
200   SCSI_DISK_DEV         *ScsiDiskDevice;
201   BOOLEAN               Temp;
202   UINT8                 Index;
203   UINT8                 MaxRetry;
204   BOOLEAN               NeedRetry;
205   BOOLEAN               MustReadCapacity;
206 
207   MustReadCapacity = TRUE;
208 
209   ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));
210   if (ScsiDiskDevice == NULL) {
211     return EFI_OUT_OF_RESOURCES;
212   }
213 
214   Status = gBS->OpenProtocol (
215                   Controller,
216                   &gEfiScsiIoProtocolGuid,
217                   (VOID **) &ScsiIo,
218                   This->DriverBindingHandle,
219                   Controller,
220                   EFI_OPEN_PROTOCOL_BY_DRIVER
221                   );
222   if (EFI_ERROR (Status)) {
223     FreePool (ScsiDiskDevice);
224     return Status;
225   }
226 
227   ScsiDiskDevice->Signature                         = SCSI_DISK_DEV_SIGNATURE;
228   ScsiDiskDevice->ScsiIo                            = ScsiIo;
229   ScsiDiskDevice->BlkIo.Revision                    = EFI_BLOCK_IO_PROTOCOL_REVISION3;
230   ScsiDiskDevice->BlkIo.Media                       = &ScsiDiskDevice->BlkIoMedia;
231   ScsiDiskDevice->BlkIo.Media->IoAlign              = ScsiIo->IoAlign;
232   ScsiDiskDevice->BlkIo.Reset                       = ScsiDiskReset;
233   ScsiDiskDevice->BlkIo.ReadBlocks                  = ScsiDiskReadBlocks;
234   ScsiDiskDevice->BlkIo.WriteBlocks                 = ScsiDiskWriteBlocks;
235   ScsiDiskDevice->BlkIo.FlushBlocks                 = ScsiDiskFlushBlocks;
236   ScsiDiskDevice->BlkIo2.Media                      = &ScsiDiskDevice->BlkIoMedia;
237   ScsiDiskDevice->BlkIo2.Reset                      = ScsiDiskResetEx;
238   ScsiDiskDevice->BlkIo2.ReadBlocksEx               = ScsiDiskReadBlocksEx;
239   ScsiDiskDevice->BlkIo2.WriteBlocksEx              = ScsiDiskWriteBlocksEx;
240   ScsiDiskDevice->BlkIo2.FlushBlocksEx              = ScsiDiskFlushBlocksEx;
241   ScsiDiskDevice->EraseBlock.Revision               = EFI_ERASE_BLOCK_PROTOCOL_REVISION;
242   ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
243   ScsiDiskDevice->EraseBlock.EraseBlocks            = ScsiDiskEraseBlocks;
244   ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt           = 1;
245   ScsiDiskDevice->BlockLimitsVpdSupported           = FALSE;
246   ScsiDiskDevice->Handle                            = Controller;
247   InitializeListHead (&ScsiDiskDevice->AsyncTaskQueue);
248 
249   ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
250   switch (ScsiDiskDevice->DeviceType) {
251   case EFI_SCSI_TYPE_DISK:
252     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
253     MustReadCapacity = TRUE;
254     break;
255 
256   case EFI_SCSI_TYPE_CDROM:
257     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
258     ScsiDiskDevice->BlkIo.Media->ReadOnly  = TRUE;
259     MustReadCapacity = FALSE;
260     break;
261   }
262   //
263   // The Sense Data Array's initial size is 6
264   //
265   ScsiDiskDevice->SenseDataNumber = 6;
266   ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (
267                                  sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
268                                  );
269   if (ScsiDiskDevice->SenseData == NULL) {
270     gBS->CloseProtocol (
271           Controller,
272           &gEfiScsiIoProtocolGuid,
273           This->DriverBindingHandle,
274           Controller
275           );
276     FreePool (ScsiDiskDevice);
277     return EFI_OUT_OF_RESOURCES;
278   }
279 
280   //
281   // Retrieve device information
282   //
283   MaxRetry = 2;
284   for (Index = 0; Index < MaxRetry; Index++) {
285     Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
286     if (!EFI_ERROR (Status)) {
287       break;
288     }
289 
290     if (!NeedRetry) {
291       FreePool (ScsiDiskDevice->SenseData);
292       gBS->CloseProtocol (
293              Controller,
294              &gEfiScsiIoProtocolGuid,
295              This->DriverBindingHandle,
296              Controller
297              );
298       FreePool (ScsiDiskDevice);
299       return EFI_DEVICE_ERROR;
300     }
301   }
302   //
303   // The second parameter "TRUE" means must
304   // retrieve media capacity
305   //
306   Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
307   if (!EFI_ERROR (Status)) {
308     //
309     // Determine if Block IO & Block IO2 should be produced on this controller
310     // handle
311     //
312     if (DetermineInstallBlockIo(Controller)) {
313       InitializeInstallDiskInfo(ScsiDiskDevice, Controller);
314       Status = gBS->InstallMultipleProtocolInterfaces (
315                       &Controller,
316                       &gEfiBlockIoProtocolGuid,
317                       &ScsiDiskDevice->BlkIo,
318                       &gEfiBlockIo2ProtocolGuid,
319                       &ScsiDiskDevice->BlkIo2,
320                       &gEfiDiskInfoProtocolGuid,
321                       &ScsiDiskDevice->DiskInfo,
322                       NULL
323                       );
324       if (!EFI_ERROR(Status)) {
325         if (DetermineInstallEraseBlock(ScsiDiskDevice, Controller)) {
326           Status = gBS->InstallProtocolInterface (
327                           &Controller,
328                           &gEfiEraseBlockProtocolGuid,
329                           EFI_NATIVE_INTERFACE,
330                           &ScsiDiskDevice->EraseBlock
331                           );
332           if (EFI_ERROR(Status)) {
333             DEBUG ((EFI_D_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status));
334           }
335         }
336         ScsiDiskDevice->ControllerNameTable = NULL;
337         AddUnicodeString2 (
338           "eng",
339           gScsiDiskComponentName.SupportedLanguages,
340           &ScsiDiskDevice->ControllerNameTable,
341           L"SCSI Disk Device",
342           TRUE
343           );
344         AddUnicodeString2 (
345           "en",
346           gScsiDiskComponentName2.SupportedLanguages,
347           &ScsiDiskDevice->ControllerNameTable,
348           L"SCSI Disk Device",
349           FALSE
350           );
351         return EFI_SUCCESS;
352       }
353     }
354   }
355 
356   gBS->FreePool (ScsiDiskDevice->SenseData);
357   gBS->FreePool (ScsiDiskDevice);
358   gBS->CloseProtocol (
359          Controller,
360          &gEfiScsiIoProtocolGuid,
361          This->DriverBindingHandle,
362          Controller
363          );
364   return Status;
365 
366 }
367 
368 
369 /**
370   Stop this driver on ControllerHandle.
371 
372   This service is called by the EFI boot service DisconnectController().
373   In order to make drivers as small as possible, there are a few calling
374   restrictions for this service. DisconnectController() must follow these
375   calling restrictions. If any other agent wishes to call Stop() it must
376   also follow these calling restrictions.
377 
378   @param  This              Protocol instance pointer.
379   @param  ControllerHandle  Handle of device to stop driver on
380   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
381                             children is zero stop the entire bus driver.
382   @param  ChildHandleBuffer List of Child Handles to Stop.
383 
384   @retval EFI_SUCCESS       This driver is removed ControllerHandle
385   @retval other             This driver was not removed from this device
386 
387 **/
388 EFI_STATUS
389 EFIAPI
ScsiDiskDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)390 ScsiDiskDriverBindingStop (
391   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
392   IN  EFI_HANDLE                      Controller,
393   IN  UINTN                           NumberOfChildren,
394   IN  EFI_HANDLE                      *ChildHandleBuffer   OPTIONAL
395   )
396 {
397   EFI_BLOCK_IO_PROTOCOL      *BlkIo;
398   EFI_ERASE_BLOCK_PROTOCOL   *EraseBlock;
399   SCSI_DISK_DEV              *ScsiDiskDevice;
400   EFI_STATUS                 Status;
401 
402   Status = gBS->OpenProtocol (
403                   Controller,
404                   &gEfiBlockIoProtocolGuid,
405                   (VOID **) &BlkIo,
406                   This->DriverBindingHandle,
407                   Controller,
408                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
409                   );
410   if (EFI_ERROR (Status)) {
411     return Status;
412   }
413 
414   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);
415 
416   //
417   // Wait for the BlockIo2 requests queue to become empty
418   //
419   while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue));
420 
421   //
422   // If Erase Block Protocol is installed, then uninstall this protocol.
423   //
424   Status = gBS->OpenProtocol (
425                   Controller,
426                   &gEfiEraseBlockProtocolGuid,
427                   (VOID **) &EraseBlock,
428                   This->DriverBindingHandle,
429                   Controller,
430                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
431                   );
432 
433   if (!EFI_ERROR (Status)) {
434     Status = gBS->UninstallProtocolInterface (
435                     Controller,
436                     &gEfiEraseBlockProtocolGuid,
437                     &ScsiDiskDevice->EraseBlock
438                     );
439     if (EFI_ERROR (Status)) {
440       return Status;
441     }
442   }
443 
444   Status = gBS->UninstallMultipleProtocolInterfaces (
445                   Controller,
446                   &gEfiBlockIoProtocolGuid,
447                   &ScsiDiskDevice->BlkIo,
448                   &gEfiBlockIo2ProtocolGuid,
449                   &ScsiDiskDevice->BlkIo2,
450                   &gEfiDiskInfoProtocolGuid,
451                   &ScsiDiskDevice->DiskInfo,
452                   NULL
453                   );
454   if (!EFI_ERROR (Status)) {
455     gBS->CloseProtocol (
456            Controller,
457            &gEfiScsiIoProtocolGuid,
458            This->DriverBindingHandle,
459            Controller
460            );
461 
462     ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
463 
464     return EFI_SUCCESS;
465   }
466   //
467   // errors met
468   //
469   return Status;
470 }
471 
472 /**
473   Reset SCSI Disk.
474 
475 
476   @param  This                 The pointer of EFI_BLOCK_IO_PROTOCOL
477   @param  ExtendedVerification The flag about if extend verificate
478 
479   @retval EFI_SUCCESS          The device was reset.
480   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
481                                not be reset.
482   @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
483 
484 **/
485 EFI_STATUS
486 EFIAPI
ScsiDiskReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)487 ScsiDiskReset (
488   IN  EFI_BLOCK_IO_PROTOCOL   *This,
489   IN  BOOLEAN                 ExtendedVerification
490   )
491 {
492   EFI_TPL       OldTpl;
493   SCSI_DISK_DEV *ScsiDiskDevice;
494   EFI_STATUS    Status;
495 
496   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
497 
498   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_BLKIO (This);
499 
500   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
501 
502   if (EFI_ERROR (Status)) {
503     if (Status == EFI_UNSUPPORTED) {
504       Status = EFI_SUCCESS;
505     } else {
506       Status = EFI_DEVICE_ERROR;
507       goto Done;
508     }
509   }
510 
511   if (!ExtendedVerification) {
512     goto Done;
513   }
514 
515   Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
516 
517   if (EFI_ERROR (Status)) {
518     Status = EFI_DEVICE_ERROR;
519     goto Done;
520   }
521 
522 Done:
523   gBS->RestoreTPL (OldTpl);
524   return Status;
525 }
526 
527 /**
528   The function is to Read Block from SCSI Disk.
529 
530   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
531   @param  MediaId    The Id of Media detected
532   @param  Lba        The logic block address
533   @param  BufferSize The size of Buffer
534   @param  Buffer     The buffer to fill the read out data
535 
536   @retval EFI_SUCCESS           Successfully to read out block.
537   @retval EFI_DEVICE_ERROR      Fail to detect media.
538   @retval EFI_NO_MEDIA          Media is not present.
539   @retval EFI_MEDIA_CHANGED     Media has changed.
540   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
541   @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
542 
543 **/
544 EFI_STATUS
545 EFIAPI
ScsiDiskReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)546 ScsiDiskReadBlocks (
547   IN  EFI_BLOCK_IO_PROTOCOL   *This,
548   IN  UINT32                  MediaId,
549   IN  EFI_LBA                 Lba,
550   IN  UINTN                   BufferSize,
551   OUT VOID                    *Buffer
552   )
553 {
554   SCSI_DISK_DEV       *ScsiDiskDevice;
555   EFI_BLOCK_IO_MEDIA  *Media;
556   EFI_STATUS          Status;
557   UINTN               BlockSize;
558   UINTN               NumberOfBlocks;
559   BOOLEAN             MediaChange;
560   EFI_TPL             OldTpl;
561 
562   MediaChange    = FALSE;
563   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
564   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
565   Media          = ScsiDiskDevice->BlkIo.Media;
566 
567   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
568 
569     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
570     if (EFI_ERROR (Status)) {
571       Status = EFI_DEVICE_ERROR;
572       goto Done;
573     }
574 
575     if (MediaChange) {
576       gBS->ReinstallProtocolInterface (
577             ScsiDiskDevice->Handle,
578             &gEfiBlockIoProtocolGuid,
579             &ScsiDiskDevice->BlkIo,
580             &ScsiDiskDevice->BlkIo
581             );
582       gBS->ReinstallProtocolInterface (
583              ScsiDiskDevice->Handle,
584              &gEfiBlockIo2ProtocolGuid,
585              &ScsiDiskDevice->BlkIo2,
586              &ScsiDiskDevice->BlkIo2
587              );
588       if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) {
589         gBS->ReinstallProtocolInterface (
590                ScsiDiskDevice->Handle,
591                &gEfiEraseBlockProtocolGuid,
592                &ScsiDiskDevice->EraseBlock,
593                &ScsiDiskDevice->EraseBlock
594                );
595       }
596       if (Media->MediaPresent) {
597         Status = EFI_MEDIA_CHANGED;
598       } else {
599         Status = EFI_NO_MEDIA;
600       }
601       goto Done;
602     }
603   }
604   //
605   // Get the intrinsic block size
606   //
607   BlockSize       = Media->BlockSize;
608 
609   NumberOfBlocks  = BufferSize / BlockSize;
610 
611   if (!(Media->MediaPresent)) {
612     Status = EFI_NO_MEDIA;
613     goto Done;
614   }
615 
616   if (MediaId != Media->MediaId) {
617     Status = EFI_MEDIA_CHANGED;
618     goto Done;
619   }
620 
621   if (Buffer == NULL) {
622     Status = EFI_INVALID_PARAMETER;
623     goto Done;
624   }
625 
626   if (BufferSize == 0) {
627     Status = EFI_SUCCESS;
628     goto Done;
629   }
630 
631   if (BufferSize % BlockSize != 0) {
632     Status = EFI_BAD_BUFFER_SIZE;
633     goto Done;
634   }
635 
636   if (Lba > Media->LastBlock) {
637     Status = EFI_INVALID_PARAMETER;
638     goto Done;
639   }
640 
641   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
642     Status = EFI_INVALID_PARAMETER;
643     goto Done;
644   }
645 
646   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
647     Status = EFI_INVALID_PARAMETER;
648     goto Done;
649   }
650 
651   //
652   // If all the parameters are valid, then perform read sectors command
653   // to transfer data from device to host.
654   //
655   Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
656 
657 Done:
658   gBS->RestoreTPL (OldTpl);
659   return Status;
660 }
661 
662 /**
663   The function is to Write Block to SCSI Disk.
664 
665   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL
666   @param  MediaId    The Id of Media detected
667   @param  Lba        The logic block address
668   @param  BufferSize The size of Buffer
669   @param  Buffer     The buffer to fill the read out data
670 
671   @retval EFI_SUCCESS           Successfully to read out block.
672   @retval EFI_WRITE_PROTECTED   The device can not be written to.
673   @retval EFI_DEVICE_ERROR      Fail to detect media.
674   @retval EFI_NO_MEDIA          Media is not present.
675   @retval EFI_MEDIA_CHNAGED     Media has changed.
676   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
677   @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
678 
679 **/
680 EFI_STATUS
681 EFIAPI
ScsiDiskWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)682 ScsiDiskWriteBlocks (
683   IN  EFI_BLOCK_IO_PROTOCOL   *This,
684   IN  UINT32                  MediaId,
685   IN  EFI_LBA                 Lba,
686   IN  UINTN                   BufferSize,
687   IN  VOID                    *Buffer
688   )
689 {
690   SCSI_DISK_DEV       *ScsiDiskDevice;
691   EFI_BLOCK_IO_MEDIA  *Media;
692   EFI_STATUS          Status;
693   UINTN               BlockSize;
694   UINTN               NumberOfBlocks;
695   BOOLEAN             MediaChange;
696   EFI_TPL             OldTpl;
697 
698   MediaChange    = FALSE;
699   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
700   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
701   Media          = ScsiDiskDevice->BlkIo.Media;
702 
703   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
704 
705     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
706     if (EFI_ERROR (Status)) {
707       Status = EFI_DEVICE_ERROR;
708       goto Done;
709     }
710 
711     if (MediaChange) {
712       gBS->ReinstallProtocolInterface (
713             ScsiDiskDevice->Handle,
714             &gEfiBlockIoProtocolGuid,
715             &ScsiDiskDevice->BlkIo,
716             &ScsiDiskDevice->BlkIo
717             );
718       gBS->ReinstallProtocolInterface (
719              ScsiDiskDevice->Handle,
720              &gEfiBlockIo2ProtocolGuid,
721              &ScsiDiskDevice->BlkIo2,
722              &ScsiDiskDevice->BlkIo2
723              );
724       if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) {
725         gBS->ReinstallProtocolInterface (
726                ScsiDiskDevice->Handle,
727                &gEfiEraseBlockProtocolGuid,
728                &ScsiDiskDevice->EraseBlock,
729                &ScsiDiskDevice->EraseBlock
730                );
731       }
732       if (Media->MediaPresent) {
733         Status = EFI_MEDIA_CHANGED;
734       } else {
735         Status = EFI_NO_MEDIA;
736       }
737       goto Done;
738     }
739   }
740   //
741   // Get the intrinsic block size
742   //
743   BlockSize       = Media->BlockSize;
744 
745   NumberOfBlocks  = BufferSize / BlockSize;
746 
747   if (!(Media->MediaPresent)) {
748     Status = EFI_NO_MEDIA;
749     goto Done;
750   }
751 
752   if (MediaId != Media->MediaId) {
753     Status = EFI_MEDIA_CHANGED;
754     goto Done;
755   }
756 
757   if (Media->ReadOnly) {
758     Status = EFI_WRITE_PROTECTED;
759     goto Done;
760   }
761 
762   if (BufferSize == 0) {
763     Status = EFI_SUCCESS;
764     goto Done;
765   }
766 
767   if (Buffer == NULL) {
768     Status = EFI_INVALID_PARAMETER;
769     goto Done;
770   }
771 
772   if (BufferSize % BlockSize != 0) {
773     Status = EFI_BAD_BUFFER_SIZE;
774     goto Done;
775   }
776 
777   if (Lba > Media->LastBlock) {
778     Status = EFI_INVALID_PARAMETER;
779     goto Done;
780   }
781 
782   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
783     Status = EFI_INVALID_PARAMETER;
784     goto Done;
785   }
786 
787   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
788     Status = EFI_INVALID_PARAMETER;
789     goto Done;
790   }
791   //
792   // if all the parameters are valid, then perform read sectors command
793   // to transfer data from device to host.
794   //
795   Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
796 
797 Done:
798   gBS->RestoreTPL (OldTpl);
799   return Status;
800 }
801 
802 /**
803   Flush Block to Disk.
804 
805   EFI_SUCCESS is returned directly.
806 
807   @param  This              The pointer of EFI_BLOCK_IO_PROTOCOL
808 
809   @retval EFI_SUCCESS       All outstanding data was written to the device
810 
811 **/
812 EFI_STATUS
813 EFIAPI
ScsiDiskFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)814 ScsiDiskFlushBlocks (
815   IN  EFI_BLOCK_IO_PROTOCOL   *This
816   )
817 {
818   //
819   // return directly
820   //
821   return EFI_SUCCESS;
822 }
823 
824 
825 /**
826   Reset SCSI Disk.
827 
828   @param  This                 The pointer of EFI_BLOCK_IO2_PROTOCOL.
829   @param  ExtendedVerification The flag about if extend verificate.
830 
831   @retval EFI_SUCCESS          The device was reset.
832   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
833                                not be reset.
834   @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
835 
836 **/
837 EFI_STATUS
838 EFIAPI
ScsiDiskResetEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN BOOLEAN ExtendedVerification)839 ScsiDiskResetEx (
840   IN  EFI_BLOCK_IO2_PROTOCOL  *This,
841   IN  BOOLEAN                 ExtendedVerification
842   )
843 {
844   EFI_TPL       OldTpl;
845   SCSI_DISK_DEV *ScsiDiskDevice;
846   EFI_STATUS    Status;
847 
848   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
849 
850   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_BLKIO2 (This);
851 
852   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
853 
854   if (EFI_ERROR (Status)) {
855     if (Status == EFI_UNSUPPORTED) {
856       Status = EFI_SUCCESS;
857     } else {
858       Status = EFI_DEVICE_ERROR;
859       goto Done;
860     }
861   }
862 
863   if (!ExtendedVerification) {
864     goto Done;
865   }
866 
867   Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
868 
869   if (EFI_ERROR (Status)) {
870     Status = EFI_DEVICE_ERROR;
871     goto Done;
872   }
873 
874 Done:
875   gBS->RestoreTPL (OldTpl);
876   return Status;
877 }
878 
879 /**
880   The function is to Read Block from SCSI Disk.
881 
882   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
883   @param  MediaId    The Id of Media detected.
884   @param  Lba        The logic block address.
885   @param  Token      A pointer to the token associated with the transaction.
886   @param  BufferSize The size of Buffer.
887   @param  Buffer     The buffer to fill the read out data.
888 
889   @retval EFI_SUCCESS           The read request was queued if Token-> Event is
890                                 not NULL. The data was read correctly from the
891                                 device if theToken-> Event is NULL.
892   @retval EFI_DEVICE_ERROR      The device reported an error while attempting
893                                 to perform the read operation.
894   @retval EFI_NO_MEDIA          There is no media in the device.
895   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
896   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of
897                                 the intrinsic block size of the device.
898   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
899                                 valid, or the buffer is not on proper
900                                 alignment.
901   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
902                                 lack of resources.
903 
904 **/
905 EFI_STATUS
906 EFIAPI
ScsiDiskReadBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,OUT VOID * Buffer)907 ScsiDiskReadBlocksEx (
908   IN     EFI_BLOCK_IO2_PROTOCOL   *This,
909   IN     UINT32                   MediaId,
910   IN     EFI_LBA                  Lba,
911   IN OUT EFI_BLOCK_IO2_TOKEN      *Token,
912   IN     UINTN                    BufferSize,
913   OUT    VOID                     *Buffer
914   )
915 {
916   SCSI_DISK_DEV       *ScsiDiskDevice;
917   EFI_BLOCK_IO_MEDIA  *Media;
918   EFI_STATUS          Status;
919   UINTN               BlockSize;
920   UINTN               NumberOfBlocks;
921   BOOLEAN             MediaChange;
922   EFI_TPL             OldTpl;
923 
924   MediaChange    = FALSE;
925   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
926   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
927   Media          = ScsiDiskDevice->BlkIo.Media;
928 
929   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
930 
931     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
932     if (EFI_ERROR (Status)) {
933       Status = EFI_DEVICE_ERROR;
934       goto Done;
935     }
936 
937     if (MediaChange) {
938       gBS->ReinstallProtocolInterface (
939             ScsiDiskDevice->Handle,
940             &gEfiBlockIoProtocolGuid,
941             &ScsiDiskDevice->BlkIo,
942             &ScsiDiskDevice->BlkIo
943             );
944       gBS->ReinstallProtocolInterface (
945              ScsiDiskDevice->Handle,
946              &gEfiBlockIo2ProtocolGuid,
947              &ScsiDiskDevice->BlkIo2,
948              &ScsiDiskDevice->BlkIo2
949              );
950       if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) {
951         gBS->ReinstallProtocolInterface (
952                ScsiDiskDevice->Handle,
953                &gEfiEraseBlockProtocolGuid,
954                &ScsiDiskDevice->EraseBlock,
955                &ScsiDiskDevice->EraseBlock
956                );
957       }
958       if (Media->MediaPresent) {
959         Status = EFI_MEDIA_CHANGED;
960       } else {
961         Status = EFI_NO_MEDIA;
962       }
963       goto Done;
964     }
965   }
966   //
967   // Get the intrinsic block size
968   //
969   BlockSize       = Media->BlockSize;
970 
971   NumberOfBlocks  = BufferSize / BlockSize;
972 
973   if (!(Media->MediaPresent)) {
974     Status = EFI_NO_MEDIA;
975     goto Done;
976   }
977 
978   if (MediaId != Media->MediaId) {
979     Status = EFI_MEDIA_CHANGED;
980     goto Done;
981   }
982 
983   if (Buffer == NULL) {
984     Status = EFI_INVALID_PARAMETER;
985     goto Done;
986   }
987 
988   if (BufferSize == 0) {
989     if ((Token != NULL) && (Token->Event != NULL)) {
990       Token->TransactionStatus = EFI_SUCCESS;
991       gBS->SignalEvent (Token->Event);
992     }
993 
994     Status = EFI_SUCCESS;
995     goto Done;
996   }
997 
998   if (BufferSize % BlockSize != 0) {
999     Status = EFI_BAD_BUFFER_SIZE;
1000     goto Done;
1001   }
1002 
1003   if (Lba > Media->LastBlock) {
1004     Status = EFI_INVALID_PARAMETER;
1005     goto Done;
1006   }
1007 
1008   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1009     Status = EFI_INVALID_PARAMETER;
1010     goto Done;
1011   }
1012 
1013   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
1014     Status = EFI_INVALID_PARAMETER;
1015     goto Done;
1016   }
1017 
1018   //
1019   // If all the parameters are valid, then perform read sectors command
1020   // to transfer data from device to host.
1021   //
1022   if ((Token != NULL) && (Token->Event != NULL)) {
1023     Token->TransactionStatus = EFI_SUCCESS;
1024     Status = ScsiDiskAsyncReadSectors (
1025                ScsiDiskDevice,
1026                Buffer,
1027                Lba,
1028                NumberOfBlocks,
1029                Token
1030                );
1031   } else {
1032     Status = ScsiDiskReadSectors (
1033                ScsiDiskDevice,
1034                Buffer,
1035                Lba,
1036                NumberOfBlocks
1037                );
1038   }
1039 
1040 Done:
1041   gBS->RestoreTPL (OldTpl);
1042   return Status;
1043 }
1044 
1045 /**
1046   The function is to Write Block to SCSI Disk.
1047 
1048   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
1049   @param  MediaId    The Id of Media detected.
1050   @param  Lba        The logic block address.
1051   @param  Token      A pointer to the token associated with the transaction.
1052   @param  BufferSize The size of Buffer.
1053   @param  Buffer     The buffer to fill the read out data.
1054 
1055   @retval EFI_SUCCESS           The data were written correctly to the device.
1056   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
1057   @retval EFI_NO_MEDIA          There is no media in the device.
1058   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
1059   @retval EFI_DEVICE_ERROR      The device reported an error while attempting
1060                                 to perform the write operation.
1061   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of
1062                                 the intrinsic block size of the device.
1063   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1064                                 valid, or the buffer is not on proper
1065                                 alignment.
1066 
1067 **/
1068 EFI_STATUS
1069 EFIAPI
ScsiDiskWriteBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,IN VOID * Buffer)1070 ScsiDiskWriteBlocksEx (
1071   IN     EFI_BLOCK_IO2_PROTOCOL *This,
1072   IN     UINT32                 MediaId,
1073   IN     EFI_LBA                Lba,
1074   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
1075   IN     UINTN                  BufferSize,
1076   IN     VOID                   *Buffer
1077   )
1078 {
1079   SCSI_DISK_DEV       *ScsiDiskDevice;
1080   EFI_BLOCK_IO_MEDIA  *Media;
1081   EFI_STATUS          Status;
1082   UINTN               BlockSize;
1083   UINTN               NumberOfBlocks;
1084   BOOLEAN             MediaChange;
1085   EFI_TPL             OldTpl;
1086 
1087   MediaChange    = FALSE;
1088   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
1089   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1090   Media          = ScsiDiskDevice->BlkIo.Media;
1091 
1092   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1093 
1094     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1095     if (EFI_ERROR (Status)) {
1096       Status = EFI_DEVICE_ERROR;
1097       goto Done;
1098     }
1099 
1100     if (MediaChange) {
1101       gBS->ReinstallProtocolInterface (
1102             ScsiDiskDevice->Handle,
1103             &gEfiBlockIoProtocolGuid,
1104             &ScsiDiskDevice->BlkIo,
1105             &ScsiDiskDevice->BlkIo
1106             );
1107       gBS->ReinstallProtocolInterface (
1108              ScsiDiskDevice->Handle,
1109              &gEfiBlockIo2ProtocolGuid,
1110              &ScsiDiskDevice->BlkIo2,
1111              &ScsiDiskDevice->BlkIo2
1112              );
1113       if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1114         gBS->ReinstallProtocolInterface (
1115                ScsiDiskDevice->Handle,
1116                &gEfiEraseBlockProtocolGuid,
1117                &ScsiDiskDevice->EraseBlock,
1118                &ScsiDiskDevice->EraseBlock
1119                );
1120       }
1121       if (Media->MediaPresent) {
1122         Status = EFI_MEDIA_CHANGED;
1123       } else {
1124         Status = EFI_NO_MEDIA;
1125       }
1126       goto Done;
1127     }
1128   }
1129   //
1130   // Get the intrinsic block size
1131   //
1132   BlockSize       = Media->BlockSize;
1133 
1134   NumberOfBlocks  = BufferSize / BlockSize;
1135 
1136   if (!(Media->MediaPresent)) {
1137     Status = EFI_NO_MEDIA;
1138     goto Done;
1139   }
1140 
1141   if (MediaId != Media->MediaId) {
1142     Status = EFI_MEDIA_CHANGED;
1143     goto Done;
1144   }
1145 
1146   if (Media->ReadOnly) {
1147     Status = EFI_WRITE_PROTECTED;
1148     goto Done;
1149   }
1150 
1151   if (BufferSize == 0) {
1152     if ((Token != NULL) && (Token->Event != NULL)) {
1153       Token->TransactionStatus = EFI_SUCCESS;
1154       gBS->SignalEvent (Token->Event);
1155     }
1156 
1157     Status = EFI_SUCCESS;
1158     goto Done;
1159   }
1160 
1161   if (Buffer == NULL) {
1162     Status = EFI_INVALID_PARAMETER;
1163     goto Done;
1164   }
1165 
1166   if (BufferSize % BlockSize != 0) {
1167     Status = EFI_BAD_BUFFER_SIZE;
1168     goto Done;
1169   }
1170 
1171   if (Lba > Media->LastBlock) {
1172     Status = EFI_INVALID_PARAMETER;
1173     goto Done;
1174   }
1175 
1176   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1177     Status = EFI_INVALID_PARAMETER;
1178     goto Done;
1179   }
1180 
1181   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
1182     Status = EFI_INVALID_PARAMETER;
1183     goto Done;
1184   }
1185 
1186   //
1187   // if all the parameters are valid, then perform write sectors command
1188   // to transfer data from device to host.
1189   //
1190   if ((Token != NULL) && (Token->Event != NULL)) {
1191     Token->TransactionStatus = EFI_SUCCESS;
1192     Status = ScsiDiskAsyncWriteSectors (
1193                ScsiDiskDevice,
1194                Buffer,
1195                Lba,
1196                NumberOfBlocks,
1197                Token
1198                );
1199   } else {
1200     Status = ScsiDiskWriteSectors (
1201                ScsiDiskDevice,
1202                Buffer,
1203                Lba,
1204                NumberOfBlocks
1205                );
1206   }
1207 
1208 Done:
1209   gBS->RestoreTPL (OldTpl);
1210   return Status;
1211 }
1212 
1213 /**
1214   Flush the Block Device.
1215 
1216   @param  This       Indicates a pointer to the calling context.
1217   @param  Token      A pointer to the token associated with the transaction.
1218 
1219   @retval EFI_SUCCESS         All outstanding data was written to the device.
1220   @retval EFI_DEVICE_ERROR    The device reported an error while attempting to
1221                               write data.
1222   @retval EFI_WRITE_PROTECTED The device cannot be written to.
1223   @retval EFI_NO_MEDIA        There is no media in the device.
1224   @retval EFI_MEDIA_CHANGED   The MediaId is not for the current media.
1225 
1226 **/
1227 EFI_STATUS
1228 EFIAPI
ScsiDiskFlushBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN OUT EFI_BLOCK_IO2_TOKEN * Token)1229 ScsiDiskFlushBlocksEx (
1230   IN     EFI_BLOCK_IO2_PROTOCOL  *This,
1231   IN OUT EFI_BLOCK_IO2_TOKEN     *Token
1232   )
1233 {
1234   SCSI_DISK_DEV       *ScsiDiskDevice;
1235   EFI_BLOCK_IO_MEDIA  *Media;
1236   EFI_STATUS          Status;
1237   BOOLEAN             MediaChange;
1238   EFI_TPL             OldTpl;
1239 
1240   MediaChange    = FALSE;
1241   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
1242   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1243   Media          = ScsiDiskDevice->BlkIo.Media;
1244 
1245   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1246 
1247     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1248     if (EFI_ERROR (Status)) {
1249       Status = EFI_DEVICE_ERROR;
1250       goto Done;
1251     }
1252 
1253     if (MediaChange) {
1254       gBS->ReinstallProtocolInterface (
1255             ScsiDiskDevice->Handle,
1256             &gEfiBlockIoProtocolGuid,
1257             &ScsiDiskDevice->BlkIo,
1258             &ScsiDiskDevice->BlkIo
1259             );
1260       gBS->ReinstallProtocolInterface (
1261              ScsiDiskDevice->Handle,
1262              &gEfiBlockIo2ProtocolGuid,
1263              &ScsiDiskDevice->BlkIo2,
1264              &ScsiDiskDevice->BlkIo2
1265              );
1266       if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1267         gBS->ReinstallProtocolInterface (
1268                ScsiDiskDevice->Handle,
1269                &gEfiEraseBlockProtocolGuid,
1270                &ScsiDiskDevice->EraseBlock,
1271                &ScsiDiskDevice->EraseBlock
1272                );
1273       }
1274       if (Media->MediaPresent) {
1275         Status = EFI_MEDIA_CHANGED;
1276       } else {
1277         Status = EFI_NO_MEDIA;
1278       }
1279       goto Done;
1280     }
1281   }
1282 
1283   if (!(Media->MediaPresent)) {
1284     Status = EFI_NO_MEDIA;
1285     goto Done;
1286   }
1287 
1288   if (Media->ReadOnly) {
1289     Status = EFI_WRITE_PROTECTED;
1290     goto Done;
1291   }
1292 
1293   //
1294   // Wait for the BlockIo2 requests queue to become empty
1295   //
1296   while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue));
1297 
1298   Status = EFI_SUCCESS;
1299 
1300   //
1301   // Signal caller event
1302   //
1303   if ((Token != NULL) && (Token->Event != NULL)) {
1304     Token->TransactionStatus = EFI_SUCCESS;
1305     gBS->SignalEvent (Token->Event);
1306   }
1307 
1308 Done:
1309   gBS->RestoreTPL (OldTpl);
1310   return Status;
1311 }
1312 
1313 
1314 /**
1315   Internal helper notify function which process the result of an asynchronous
1316   SCSI UNMAP Command and signal the event passed from EraseBlocks.
1317 
1318   @param  Event    The instance of EFI_EVENT.
1319   @param  Context  The parameter passed in.
1320 
1321 **/
1322 VOID
1323 EFIAPI
ScsiDiskAsyncUnmapNotify(IN EFI_EVENT Event,IN VOID * Context)1324 ScsiDiskAsyncUnmapNotify (
1325   IN  EFI_EVENT  Event,
1326   IN  VOID       *Context
1327   )
1328 {
1329   SCSI_ERASEBLK_REQUEST            *EraseBlkReq;
1330   EFI_SCSI_IO_SCSI_REQUEST_PACKET  *CommandPacket;
1331   EFI_ERASE_BLOCK_TOKEN            *Token;
1332   EFI_STATUS                       Status;
1333 
1334   gBS->CloseEvent (Event);
1335 
1336   EraseBlkReq              = (SCSI_ERASEBLK_REQUEST *) Context;
1337   CommandPacket            = &EraseBlkReq->CommandPacket;
1338   Token                    = EraseBlkReq->Token;
1339   Token->TransactionStatus = EFI_SUCCESS;
1340 
1341   Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
1342   if (EFI_ERROR(Status)) {
1343     DEBUG ((
1344       EFI_D_ERROR,
1345       "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1346       CommandPacket->HostAdapterStatus
1347       ));
1348 
1349     Token->TransactionStatus = Status;
1350     goto Done;
1351   }
1352 
1353   Status = CheckTargetStatus (CommandPacket->TargetStatus);
1354   if (EFI_ERROR(Status)) {
1355     DEBUG ((
1356       EFI_D_ERROR,
1357       "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1358       CommandPacket->HostAdapterStatus
1359       ));
1360 
1361     Token->TransactionStatus = Status;
1362     goto Done;
1363   }
1364 
1365 Done:
1366   RemoveEntryList (&EraseBlkReq->Link);
1367   FreePool (CommandPacket->OutDataBuffer);
1368   FreePool (EraseBlkReq->CommandPacket.Cdb);
1369   FreePool (EraseBlkReq);
1370 
1371   gBS->SignalEvent (Token->Event);
1372 }
1373 
1374 /**
1375   Require the device server to cause one or more LBAs to be unmapped.
1376 
1377   @param  ScsiDiskDevice         The pointer of ScsiDiskDevice.
1378   @param  Lba                    The start block number.
1379   @param  Blocks                 Total block number to be unmapped.
1380   @param  Token                  The pointer to the token associated with the
1381                                  non-blocking erase block request.
1382 
1383   @retval EFI_SUCCESS            Target blocks have been successfully unmapped.
1384   @retval EFI_DEVICE_ERROR       Fail to unmap the target blocks.
1385 
1386 **/
1387 EFI_STATUS
ScsiDiskUnmap(IN SCSI_DISK_DEV * ScsiDiskDevice,IN UINT64 Lba,IN UINTN Blocks,IN EFI_ERASE_BLOCK_TOKEN * Token OPTIONAL)1388 ScsiDiskUnmap (
1389   IN SCSI_DISK_DEV                 *ScsiDiskDevice,
1390   IN UINT64                        Lba,
1391   IN UINTN                         Blocks,
1392   IN EFI_ERASE_BLOCK_TOKEN         *Token            OPTIONAL
1393   )
1394 {
1395   EFI_SCSI_IO_PROTOCOL             *ScsiIo;
1396   SCSI_ERASEBLK_REQUEST            *EraseBlkReq;
1397   EFI_SCSI_IO_SCSI_REQUEST_PACKET  *CommandPacket;
1398   EFI_SCSI_DISK_UNMAP_BLOCK_DESP   *BlkDespPtr;
1399   EFI_STATUS                       Status;
1400   EFI_STATUS                       ReturnStatus;
1401   UINT8                            *Cdb;
1402   UINT32                           MaxLbaCnt;
1403   UINT32                           MaxBlkDespCnt;
1404   UINT32                           BlkDespCnt;
1405   UINT16                           UnmapParamListLen;
1406   VOID                             *UnmapParamList;
1407   EFI_EVENT                        AsyncUnmapEvent;
1408   EFI_TPL                          OldTpl;
1409 
1410   ScsiIo          = ScsiDiskDevice->ScsiIo;
1411   MaxLbaCnt       = ScsiDiskDevice->UnmapInfo.MaxLbaCnt;
1412   MaxBlkDespCnt   = ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt;
1413   EraseBlkReq     = NULL;
1414   UnmapParamList  = NULL;
1415   AsyncUnmapEvent = NULL;
1416   ReturnStatus    = EFI_SUCCESS;
1417 
1418   if (Blocks / (UINTN) MaxLbaCnt > MaxBlkDespCnt) {
1419     ReturnStatus = EFI_DEVICE_ERROR;
1420     goto Done;
1421   }
1422 
1423   EraseBlkReq = AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST));
1424   if (EraseBlkReq == NULL) {
1425     ReturnStatus = EFI_DEVICE_ERROR;
1426     goto Done;
1427   }
1428 
1429   EraseBlkReq->CommandPacket.Cdb = AllocateZeroPool (0xA);
1430   if (EraseBlkReq->CommandPacket.Cdb == NULL) {
1431     ReturnStatus = EFI_DEVICE_ERROR;
1432     goto Done;
1433   }
1434 
1435   BlkDespCnt        = (UINT32) ((Blocks - 1) / MaxLbaCnt + 1);
1436   UnmapParamListLen = (UINT16) (sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER)
1437                       + BlkDespCnt * sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP));
1438   UnmapParamList    = AllocateZeroPool (UnmapParamListLen);
1439   if (UnmapParamList == NULL) {
1440     ReturnStatus = EFI_DEVICE_ERROR;
1441     goto Done;
1442   }
1443 
1444   *((UINT16 *)UnmapParamList)     = SwapBytes16 (UnmapParamListLen - 2);
1445   *((UINT16 *)UnmapParamList + 1) = SwapBytes16 (UnmapParamListLen - sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
1446 
1447   BlkDespPtr = (EFI_SCSI_DISK_UNMAP_BLOCK_DESP *)((UINT8 *)UnmapParamList + sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
1448   while (Blocks > 0) {
1449     if (Blocks > MaxLbaCnt) {
1450       *(UINT64 *)(&BlkDespPtr->Lba)      = SwapBytes64 (Lba);
1451       *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 (MaxLbaCnt);
1452       Blocks -= MaxLbaCnt;
1453       Lba    += MaxLbaCnt;
1454     } else {
1455       *(UINT64 *)(&BlkDespPtr->Lba)      = SwapBytes64 (Lba);
1456       *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 ((UINT32) Blocks);
1457       Blocks = 0;
1458     }
1459 
1460     BlkDespPtr++;
1461   }
1462 
1463   CommandPacket                    = &EraseBlkReq->CommandPacket;
1464   CommandPacket->Timeout           = SCSI_DISK_TIMEOUT;
1465   CommandPacket->OutDataBuffer     = UnmapParamList;
1466   CommandPacket->OutTransferLength = UnmapParamListLen;
1467   CommandPacket->CdbLength         = 0xA;
1468   CommandPacket->DataDirection     = EFI_SCSI_DATA_OUT;
1469   //
1470   // Fill Cdb for UNMAP Command
1471   //
1472   Cdb    = CommandPacket->Cdb;
1473   Cdb[0] = EFI_SCSI_OP_UNMAP;
1474   WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 (UnmapParamListLen));
1475 
1476   if ((Token != NULL) && (Token->Event != NULL)) {
1477     //
1478     // Non-blocking UNMAP request
1479     //
1480     Status = gBS->CreateEvent (
1481                     EVT_NOTIFY_SIGNAL,
1482                     TPL_NOTIFY,
1483                     ScsiDiskAsyncUnmapNotify,
1484                     EraseBlkReq,
1485                     &AsyncUnmapEvent
1486                     );
1487     if (EFI_ERROR(Status)) {
1488       ReturnStatus = EFI_DEVICE_ERROR;
1489       goto Done;
1490     }
1491 
1492     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1493     InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &EraseBlkReq->Link);
1494     gBS->RestoreTPL (OldTpl);
1495 
1496     EraseBlkReq->Token = Token;
1497 
1498     Status = ScsiIo->ExecuteScsiCommand (
1499                        ScsiIo,
1500                        CommandPacket,
1501                        AsyncUnmapEvent
1502                        );
1503     if (EFI_ERROR(Status)) {
1504       ReturnStatus = EFI_DEVICE_ERROR;
1505 
1506       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1507       RemoveEntryList (&EraseBlkReq->Link);
1508       gBS->RestoreTPL (OldTpl);
1509 
1510       goto Done;
1511     } else {
1512       //
1513       // Directly return if the non-blocking UNMAP request is queued.
1514       //
1515       return EFI_SUCCESS;
1516     }
1517   } else {
1518     //
1519     // Blocking UNMAP request
1520     //
1521     Status = ScsiIo->ExecuteScsiCommand (
1522                        ScsiIo,
1523                        CommandPacket,
1524                        NULL
1525                        );
1526     if (EFI_ERROR(Status)) {
1527       ReturnStatus = EFI_DEVICE_ERROR;
1528       goto Done;
1529     }
1530   }
1531 
1532   //
1533   // Only blocking UNMAP request will reach here.
1534   //
1535   Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
1536   if (EFI_ERROR(Status)) {
1537     DEBUG ((
1538       EFI_D_ERROR,
1539       "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1540       CommandPacket->HostAdapterStatus
1541       ));
1542 
1543     ReturnStatus = EFI_DEVICE_ERROR;
1544     goto Done;
1545   }
1546 
1547   Status = CheckTargetStatus (CommandPacket->TargetStatus);
1548   if (EFI_ERROR(Status)) {
1549     DEBUG ((
1550       EFI_D_ERROR,
1551       "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1552       CommandPacket->HostAdapterStatus
1553       ));
1554 
1555     ReturnStatus = EFI_DEVICE_ERROR;
1556     goto Done;
1557   }
1558 
1559 Done:
1560   if (EraseBlkReq != NULL) {
1561     if (EraseBlkReq->CommandPacket.Cdb != NULL) {
1562       FreePool (EraseBlkReq->CommandPacket.Cdb);
1563     }
1564     FreePool (EraseBlkReq);
1565   }
1566 
1567   if (UnmapParamList != NULL) {
1568     FreePool (UnmapParamList);
1569   }
1570 
1571   if (AsyncUnmapEvent != NULL) {
1572     gBS->CloseEvent (AsyncUnmapEvent);
1573   }
1574 
1575   return ReturnStatus;
1576 }
1577 
1578 /**
1579   Erase a specified number of device blocks.
1580 
1581   @param[in]       This           Indicates a pointer to the calling context.
1582   @param[in]       MediaId        The media ID that the erase request is for.
1583   @param[in]       Lba            The starting logical block address to be
1584                                   erased. The caller is responsible for erasing
1585                                   only legitimate locations.
1586   @param[in, out]  Token          A pointer to the token associated with the
1587                                   transaction.
1588   @param[in]       Size           The size in bytes to be erased. This must be
1589                                   a multiple of the physical block size of the
1590                                   device.
1591 
1592   @retval EFI_SUCCESS             The erase request was queued if Event is not
1593                                   NULL. The data was erased correctly to the
1594                                   device if the Event is NULL.to the device.
1595   @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
1596                                   protection.
1597   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
1598                                   to perform the erase operation.
1599   @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
1600                                   valid.
1601   @retval EFI_NO_MEDIA            There is no media in the device.
1602   @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
1603 
1604 **/
1605 EFI_STATUS
1606 EFIAPI
ScsiDiskEraseBlocks(IN EFI_ERASE_BLOCK_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_ERASE_BLOCK_TOKEN * Token,IN UINTN Size)1607 ScsiDiskEraseBlocks (
1608   IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
1609   IN     UINT32                        MediaId,
1610   IN     EFI_LBA                       Lba,
1611   IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
1612   IN     UINTN                         Size
1613   )
1614 {
1615   SCSI_DISK_DEV       *ScsiDiskDevice;
1616   EFI_BLOCK_IO_MEDIA  *Media;
1617   EFI_STATUS          Status;
1618   UINTN               BlockSize;
1619   UINTN               NumberOfBlocks;
1620   BOOLEAN             MediaChange;
1621   EFI_TPL             OldTpl;
1622 
1623   MediaChange    = FALSE;
1624   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
1625   ScsiDiskDevice = SCSI_DISK_DEV_FROM_ERASEBLK (This);
1626 
1627   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1628     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1629     if (EFI_ERROR (Status)) {
1630       Status = EFI_DEVICE_ERROR;
1631       goto Done;
1632     }
1633 
1634     if (MediaChange) {
1635       gBS->ReinstallProtocolInterface (
1636             ScsiDiskDevice->Handle,
1637             &gEfiBlockIoProtocolGuid,
1638             &ScsiDiskDevice->BlkIo,
1639             &ScsiDiskDevice->BlkIo
1640             );
1641       gBS->ReinstallProtocolInterface (
1642              ScsiDiskDevice->Handle,
1643              &gEfiBlockIo2ProtocolGuid,
1644              &ScsiDiskDevice->BlkIo2,
1645              &ScsiDiskDevice->BlkIo2
1646              );
1647       if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1648         gBS->ReinstallProtocolInterface (
1649                ScsiDiskDevice->Handle,
1650                &gEfiEraseBlockProtocolGuid,
1651                &ScsiDiskDevice->EraseBlock,
1652                &ScsiDiskDevice->EraseBlock
1653                );
1654       }
1655       Status = EFI_MEDIA_CHANGED;
1656       goto Done;
1657     }
1658   }
1659   //
1660   // Get the intrinsic block size
1661   //
1662   Media = ScsiDiskDevice->BlkIo.Media;
1663 
1664   if (!(Media->MediaPresent)) {
1665     Status = EFI_NO_MEDIA;
1666     goto Done;
1667   }
1668 
1669   if (MediaId != Media->MediaId) {
1670     Status = EFI_MEDIA_CHANGED;
1671     goto Done;
1672   }
1673 
1674   if (Media->ReadOnly) {
1675     Status = EFI_WRITE_PROTECTED;
1676     goto Done;
1677   }
1678 
1679   if (Size == 0) {
1680     if ((Token != NULL) && (Token->Event != NULL)) {
1681       Token->TransactionStatus = EFI_SUCCESS;
1682       gBS->SignalEvent (Token->Event);
1683     }
1684     Status = EFI_SUCCESS;
1685     goto Done;
1686   }
1687 
1688   BlockSize = Media->BlockSize;
1689   if ((Size % BlockSize) != 0) {
1690     Status = EFI_INVALID_PARAMETER;
1691     goto Done;
1692   }
1693 
1694   NumberOfBlocks = Size / BlockSize;
1695   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1696     Status = EFI_INVALID_PARAMETER;
1697     goto Done;
1698   }
1699 
1700   if ((Token != NULL) && (Token->Event != NULL)) {
1701     Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, Token);
1702   } else {
1703     Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, NULL);
1704   }
1705 
1706 Done:
1707   gBS->RestoreTPL (OldTpl);
1708   return Status;
1709 }
1710 
1711 
1712 /**
1713   Detect Device and read out capacity ,if error occurs, parse the sense key.
1714 
1715   @param  ScsiDiskDevice    The pointer of SCSI_DISK_DEV
1716   @param  MustReadCapacity  The flag about reading device capacity
1717   @param  MediaChange       The pointer of flag indicates if media has changed
1718 
1719   @retval EFI_DEVICE_ERROR  Indicates that error occurs
1720   @retval EFI_SUCCESS       Successfully to detect media
1721 
1722 **/
1723 EFI_STATUS
ScsiDiskDetectMedia(IN SCSI_DISK_DEV * ScsiDiskDevice,IN BOOLEAN MustReadCapacity,OUT BOOLEAN * MediaChange)1724 ScsiDiskDetectMedia (
1725   IN   SCSI_DISK_DEV   *ScsiDiskDevice,
1726   IN   BOOLEAN         MustReadCapacity,
1727   OUT  BOOLEAN         *MediaChange
1728   )
1729 {
1730   EFI_STATUS          Status;
1731   EFI_SCSI_SENSE_DATA *SenseData;
1732   UINTN               NumberOfSenseKeys;
1733   BOOLEAN             NeedRetry;
1734   BOOLEAN             NeedReadCapacity;
1735   UINT8               Retry;
1736   UINT8               MaxRetry;
1737   EFI_BLOCK_IO_MEDIA  OldMedia;
1738   UINTN               Action;
1739   EFI_EVENT           TimeoutEvt;
1740 
1741   Status              = EFI_SUCCESS;
1742   SenseData           = NULL;
1743   NumberOfSenseKeys   = 0;
1744   Retry               = 0;
1745   MaxRetry            = 3;
1746   Action              = ACTION_NO_ACTION;
1747   NeedReadCapacity    = FALSE;
1748   *MediaChange        = FALSE;
1749   TimeoutEvt          = NULL;
1750 
1751   CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
1752 
1753   Status = gBS->CreateEvent (
1754                   EVT_TIMER,
1755                   TPL_CALLBACK,
1756                   NULL,
1757                   NULL,
1758                   &TimeoutEvt
1759                   );
1760   if (EFI_ERROR (Status)) {
1761     return Status;
1762   }
1763 
1764   Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));
1765   if (EFI_ERROR (Status)) {
1766     goto EXIT;
1767   }
1768 
1769   //
1770   // Sending Test_Unit cmd to poll device status.
1771   // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1772   // We limit the upper boundary to 120 seconds.
1773   //
1774   while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
1775     Status = ScsiDiskTestUnitReady (
1776               ScsiDiskDevice,
1777               &NeedRetry,
1778               &SenseData,
1779               &NumberOfSenseKeys
1780               );
1781     if (!EFI_ERROR (Status)) {
1782       Status = DetectMediaParsingSenseKeys (
1783                  ScsiDiskDevice,
1784                  SenseData,
1785                  NumberOfSenseKeys,
1786                  &Action
1787                  );
1788       if (EFI_ERROR (Status)) {
1789         goto EXIT;
1790       } else if (Action == ACTION_RETRY_COMMAND_LATER) {
1791         continue;
1792       } else {
1793         break;
1794       }
1795     } else {
1796       Retry++;
1797       if (!NeedRetry || (Retry >= MaxRetry)) {
1798         goto EXIT;
1799       }
1800     }
1801   }
1802 
1803   if (EFI_ERROR (Status)) {
1804     goto EXIT;
1805   }
1806 
1807   //
1808   // ACTION_NO_ACTION: need not read capacity
1809   // other action code: need read capacity
1810   //
1811   if (Action == ACTION_READ_CAPACITY) {
1812     NeedReadCapacity = TRUE;
1813   }
1814 
1815   //
1816   // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1817   // retrieve capacity via Read Capacity command
1818   //
1819   if (NeedReadCapacity || MustReadCapacity) {
1820     //
1821     // retrieve media information
1822     //
1823     for (Retry = 0; Retry < MaxRetry; Retry++) {
1824       Status = ScsiDiskReadCapacity (
1825                  ScsiDiskDevice,
1826                  &NeedRetry,
1827                  &SenseData,
1828                  &NumberOfSenseKeys
1829                  );
1830       if (!EFI_ERROR (Status)) {
1831         //
1832         // analyze sense key to action
1833         //
1834         Status = DetectMediaParsingSenseKeys (
1835                    ScsiDiskDevice,
1836                    SenseData,
1837                    NumberOfSenseKeys,
1838                    &Action
1839                    );
1840         if (EFI_ERROR (Status)) {
1841           //
1842           // if Status is error, it may indicate crisis error,
1843           // so return without retry.
1844           //
1845           goto EXIT;
1846         } else if (Action == ACTION_RETRY_COMMAND_LATER) {
1847           Retry = 0;
1848           continue;
1849         } else {
1850           break;
1851         }
1852       } else {
1853         Retry++;
1854         if (!NeedRetry || (Retry >= MaxRetry)) {
1855           goto EXIT;
1856         }
1857       }
1858     }
1859 
1860     if (EFI_ERROR (Status)) {
1861       goto EXIT;
1862     }
1863   }
1864 
1865   if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
1866     //
1867     // Media change information got from the device
1868     //
1869     *MediaChange = TRUE;
1870   }
1871 
1872   if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
1873     *MediaChange = TRUE;
1874     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
1875   }
1876 
1877   if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
1878     *MediaChange = TRUE;
1879     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
1880   }
1881 
1882   if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
1883     *MediaChange = TRUE;
1884     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
1885   }
1886 
1887   if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
1888     if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
1889       //
1890       // when change from no media to media present, reset the MediaId to 1.
1891       //
1892       ScsiDiskDevice->BlkIo.Media->MediaId = 1;
1893     } else {
1894       //
1895       // when no media, reset the MediaId to zero.
1896       //
1897       ScsiDiskDevice->BlkIo.Media->MediaId = 0;
1898     }
1899 
1900     *MediaChange = TRUE;
1901   }
1902 
1903 EXIT:
1904   if (TimeoutEvt != NULL) {
1905     gBS->CloseEvent (TimeoutEvt);
1906   }
1907   return Status;
1908 }
1909 
1910 
1911 /**
1912   Send out Inquiry command to Device.
1913 
1914   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
1915   @param  NeedRetry       Indicates if needs try again when error happens
1916 
1917   @retval  EFI_DEVICE_ERROR  Indicates that error occurs
1918   @retval  EFI_SUCCESS       Successfully to detect media
1919 
1920 **/
1921 EFI_STATUS
ScsiDiskInquiryDevice(IN OUT SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry)1922 ScsiDiskInquiryDevice (
1923   IN OUT  SCSI_DISK_DEV   *ScsiDiskDevice,
1924      OUT  BOOLEAN         *NeedRetry
1925   )
1926 {
1927   UINT32                                InquiryDataLength;
1928   UINT8                                 SenseDataLength;
1929   UINT8                                 HostAdapterStatus;
1930   UINT8                                 TargetStatus;
1931   EFI_SCSI_SENSE_DATA                   *SenseDataArray;
1932   UINTN                                 NumberOfSenseKeys;
1933   EFI_STATUS                            Status;
1934   UINT8                                 MaxRetry;
1935   UINT8                                 Index;
1936   EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
1937   EFI_SCSI_BLOCK_LIMITS_VPD_PAGE        *BlockLimits;
1938   UINTN                                 PageLength;
1939 
1940   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
1941   SenseDataLength   = 0;
1942 
1943   Status = ScsiInquiryCommand (
1944             ScsiDiskDevice->ScsiIo,
1945             SCSI_DISK_TIMEOUT,
1946             NULL,
1947             &SenseDataLength,
1948             &HostAdapterStatus,
1949             &TargetStatus,
1950             (VOID *) &(ScsiDiskDevice->InquiryData),
1951             &InquiryDataLength,
1952             FALSE
1953             );
1954     //
1955     // no need to check HostAdapterStatus and TargetStatus
1956     //
1957   if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
1958     ParseInquiryData (ScsiDiskDevice);
1959 
1960     if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
1961       //
1962       // Check whether the device supports Block Limits VPD page (0xB0)
1963       //
1964       SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1965       if (SupportedVpdPages == NULL) {
1966         *NeedRetry = FALSE;
1967         return EFI_DEVICE_ERROR;
1968       }
1969       ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1970       InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
1971       SenseDataLength   = 0;
1972       Status = ScsiInquiryCommandEx (
1973                  ScsiDiskDevice->ScsiIo,
1974                  SCSI_DISK_TIMEOUT,
1975                  NULL,
1976                  &SenseDataLength,
1977                  &HostAdapterStatus,
1978                  &TargetStatus,
1979                  (VOID *) SupportedVpdPages,
1980                  &InquiryDataLength,
1981                  TRUE,
1982                  EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1983                  );
1984       if (!EFI_ERROR (Status)) {
1985         PageLength = (SupportedVpdPages->PageLength2 << 8)
1986                    |  SupportedVpdPages->PageLength1;
1987 
1988         //
1989         // Sanity checks for coping with broken devices
1990         //
1991         if (PageLength > sizeof SupportedVpdPages->SupportedVpdPageList) {
1992           DEBUG ((EFI_D_WARN,
1993             "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
1994             __FUNCTION__, (UINT32)PageLength));
1995           PageLength = 0;
1996         }
1997 
1998         if ((PageLength > 0) &&
1999             (SupportedVpdPages->SupportedVpdPageList[0] !=
2000              EFI_SCSI_PAGE_CODE_SUPPORTED_VPD)) {
2001           DEBUG ((EFI_D_WARN,
2002             "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2003             __FUNCTION__, EFI_SCSI_PAGE_CODE_SUPPORTED_VPD));
2004           PageLength = 0;
2005         }
2006 
2007         //
2008         // Locate the code for the Block Limits VPD page
2009         //
2010         for (Index = 0; Index < PageLength; Index++) {
2011           //
2012           // Sanity check
2013           //
2014           if ((Index > 0) &&
2015               (SupportedVpdPages->SupportedVpdPageList[Index] <=
2016                SupportedVpdPages->SupportedVpdPageList[Index - 1])) {
2017             DEBUG ((EFI_D_WARN,
2018               "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2019               __FUNCTION__, Index));
2020             Index = 0;
2021             PageLength = 0;
2022             break;
2023           }
2024 
2025           if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
2026             break;
2027           }
2028         }
2029 
2030         //
2031         // Query the Block Limits VPD page
2032         //
2033         if (Index < PageLength) {
2034           BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2035           if (BlockLimits == NULL) {
2036             FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2037             *NeedRetry = FALSE;
2038             return EFI_DEVICE_ERROR;
2039           }
2040           ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2041           InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
2042           SenseDataLength   = 0;
2043           Status = ScsiInquiryCommandEx (
2044                      ScsiDiskDevice->ScsiIo,
2045                      SCSI_DISK_TIMEOUT,
2046                      NULL,
2047                      &SenseDataLength,
2048                      &HostAdapterStatus,
2049                      &TargetStatus,
2050                      (VOID *) BlockLimits,
2051                      &InquiryDataLength,
2052                      TRUE,
2053                      EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2054                      );
2055           if (!EFI_ERROR (Status)) {
2056             ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
2057               (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
2058                BlockLimits->OptimalTransferLengthGranularity1;
2059 
2060             ScsiDiskDevice->UnmapInfo.MaxLbaCnt =
2061               (BlockLimits->MaximumUnmapLbaCount4 << 24) |
2062               (BlockLimits->MaximumUnmapLbaCount3 << 16) |
2063               (BlockLimits->MaximumUnmapLbaCount2 << 8)  |
2064               BlockLimits->MaximumUnmapLbaCount1;
2065             ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt =
2066               (BlockLimits->MaximumUnmapBlockDescriptorCount4 << 24) |
2067               (BlockLimits->MaximumUnmapBlockDescriptorCount3 << 16) |
2068               (BlockLimits->MaximumUnmapBlockDescriptorCount2 << 8)  |
2069               BlockLimits->MaximumUnmapBlockDescriptorCount1;
2070             ScsiDiskDevice->EraseBlock.EraseLengthGranularity =
2071               (BlockLimits->OptimalUnmapGranularity4 << 24) |
2072               (BlockLimits->OptimalUnmapGranularity3 << 16) |
2073               (BlockLimits->OptimalUnmapGranularity2 << 8)  |
2074               BlockLimits->OptimalUnmapGranularity1;
2075             if (BlockLimits->UnmapGranularityAlignmentValid != 0) {
2076               ScsiDiskDevice->UnmapInfo.GranularityAlignment =
2077                 (BlockLimits->UnmapGranularityAlignment4 << 24) |
2078                 (BlockLimits->UnmapGranularityAlignment3 << 16) |
2079                 (BlockLimits->UnmapGranularityAlignment2 << 8)  |
2080                 BlockLimits->UnmapGranularityAlignment1;
2081             }
2082 
2083             if (ScsiDiskDevice->EraseBlock.EraseLengthGranularity == 0) {
2084               //
2085               // A value of 0 indicates that the optimal unmap granularity is
2086               // not reported.
2087               //
2088               ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
2089             }
2090 
2091             ScsiDiskDevice->BlockLimitsVpdSupported = TRUE;
2092           }
2093 
2094           FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2095         }
2096       }
2097 
2098       FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2099     }
2100   }
2101 
2102   if (!EFI_ERROR (Status)) {
2103     return EFI_SUCCESS;
2104 
2105   } else if (Status == EFI_NOT_READY) {
2106     *NeedRetry = TRUE;
2107     return EFI_DEVICE_ERROR;
2108 
2109   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2110     *NeedRetry = FALSE;
2111     return EFI_DEVICE_ERROR;
2112   }
2113   //
2114   // go ahead to check HostAdapterStatus and TargetStatus
2115   // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2116   //
2117 
2118   Status = CheckHostAdapterStatus (HostAdapterStatus);
2119   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2120     *NeedRetry = TRUE;
2121     return EFI_DEVICE_ERROR;
2122   } else if (Status == EFI_DEVICE_ERROR) {
2123       //
2124       // reset the scsi channel
2125       //
2126     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2127     *NeedRetry = FALSE;
2128     return EFI_DEVICE_ERROR;
2129   }
2130 
2131   Status = CheckTargetStatus (TargetStatus);
2132   if (Status == EFI_NOT_READY) {
2133     //
2134     // reset the scsi device
2135     //
2136     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2137     *NeedRetry = TRUE;
2138     return EFI_DEVICE_ERROR;
2139 
2140   } else if (Status == EFI_DEVICE_ERROR) {
2141     *NeedRetry = FALSE;
2142     return EFI_DEVICE_ERROR;
2143   }
2144 
2145   //
2146   // if goes here, meant ScsiInquiryCommand() failed.
2147   // if ScsiDiskRequestSenseKeys() succeeds at last,
2148   // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2149   //
2150   MaxRetry = 3;
2151   for (Index = 0; Index < MaxRetry; Index++) {
2152     Status = ScsiDiskRequestSenseKeys (
2153               ScsiDiskDevice,
2154               NeedRetry,
2155               &SenseDataArray,
2156               &NumberOfSenseKeys,
2157               TRUE
2158               );
2159     if (!EFI_ERROR (Status)) {
2160       *NeedRetry = TRUE;
2161       return EFI_DEVICE_ERROR;
2162     }
2163 
2164     if (!*NeedRetry) {
2165       return EFI_DEVICE_ERROR;
2166     }
2167   }
2168   //
2169   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2170   // set *NeedRetry = FALSE to avoid the outside caller try again.
2171   //
2172   *NeedRetry = FALSE;
2173   return EFI_DEVICE_ERROR;
2174 }
2175 
2176 /**
2177   To test device.
2178 
2179   When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2180   When Test Unit Ready command encounters any error caused by host adapter or
2181   target, return error without retrieving Sense Keys.
2182 
2183   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
2184   @param  NeedRetry          The pointer of flag indicates try again
2185   @param  SenseDataArray     The pointer of an array of sense data
2186   @param  NumberOfSenseKeys  The pointer of the number of sense data array
2187 
2188   @retval EFI_DEVICE_ERROR   Indicates that error occurs
2189   @retval EFI_SUCCESS        Successfully to test unit
2190 
2191 **/
2192 EFI_STATUS
ScsiDiskTestUnitReady(IN SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry,OUT EFI_SCSI_SENSE_DATA ** SenseDataArray,OUT UINTN * NumberOfSenseKeys)2193 ScsiDiskTestUnitReady (
2194   IN  SCSI_DISK_DEV         *ScsiDiskDevice,
2195   OUT BOOLEAN               *NeedRetry,
2196   OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,
2197   OUT UINTN                 *NumberOfSenseKeys
2198   )
2199 {
2200   EFI_STATUS  Status;
2201   UINT8       SenseDataLength;
2202   UINT8       HostAdapterStatus;
2203   UINT8       TargetStatus;
2204   UINT8       Index;
2205   UINT8       MaxRetry;
2206 
2207   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2208   *NumberOfSenseKeys  = 0;
2209 
2210   //
2211   // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2212   //
2213   Status = ScsiTestUnitReadyCommand (
2214             ScsiDiskDevice->ScsiIo,
2215             SCSI_DISK_TIMEOUT,
2216             ScsiDiskDevice->SenseData,
2217             &SenseDataLength,
2218             &HostAdapterStatus,
2219             &TargetStatus
2220             );
2221   //
2222   // no need to check HostAdapterStatus and TargetStatus
2223   //
2224   if (Status == EFI_NOT_READY) {
2225     *NeedRetry = TRUE;
2226     return EFI_DEVICE_ERROR;
2227 
2228   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2229     *NeedRetry = FALSE;
2230     return EFI_DEVICE_ERROR;
2231   }
2232   //
2233   // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2234   //
2235 
2236   Status = CheckHostAdapterStatus (HostAdapterStatus);
2237   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2238     *NeedRetry = TRUE;
2239     return EFI_DEVICE_ERROR;
2240 
2241   } else if (Status == EFI_DEVICE_ERROR) {
2242     //
2243     // reset the scsi channel
2244     //
2245     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2246     *NeedRetry = FALSE;
2247     return EFI_DEVICE_ERROR;
2248   }
2249 
2250   Status = CheckTargetStatus (TargetStatus);
2251   if (Status == EFI_NOT_READY) {
2252     //
2253     // reset the scsi device
2254     //
2255     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2256     *NeedRetry = TRUE;
2257     return EFI_DEVICE_ERROR;
2258 
2259   } else if (Status == EFI_DEVICE_ERROR) {
2260     *NeedRetry = FALSE;
2261     return EFI_DEVICE_ERROR;
2262   }
2263 
2264   if (SenseDataLength != 0) {
2265     *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
2266     *SenseDataArray    = ScsiDiskDevice->SenseData;
2267     return EFI_SUCCESS;
2268   }
2269 
2270   MaxRetry = 3;
2271   for (Index = 0; Index < MaxRetry; Index++) {
2272     Status = ScsiDiskRequestSenseKeys (
2273               ScsiDiskDevice,
2274               NeedRetry,
2275               SenseDataArray,
2276               NumberOfSenseKeys,
2277               FALSE
2278               );
2279     if (!EFI_ERROR (Status)) {
2280       return EFI_SUCCESS;
2281     }
2282 
2283     if (!*NeedRetry) {
2284       return EFI_DEVICE_ERROR;
2285     }
2286   }
2287   //
2288   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2289   // set *NeedRetry = FALSE to avoid the outside caller try again.
2290   //
2291   *NeedRetry = FALSE;
2292   return EFI_DEVICE_ERROR;
2293 }
2294 
2295 /**
2296   Parsing Sense Keys which got from request sense command.
2297 
2298   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
2299   @param  SenseData          The pointer of EFI_SCSI_SENSE_DATA
2300   @param  NumberOfSenseKeys  The number of sense key
2301   @param  Action             The pointer of action which indicates what is need to do next
2302 
2303   @retval EFI_DEVICE_ERROR   Indicates that error occurs
2304   @retval EFI_SUCCESS        Successfully to complete the parsing
2305 
2306 **/
2307 EFI_STATUS
DetectMediaParsingSenseKeys(OUT SCSI_DISK_DEV * ScsiDiskDevice,IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN NumberOfSenseKeys,OUT UINTN * Action)2308 DetectMediaParsingSenseKeys (
2309   OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
2310   IN   EFI_SCSI_SENSE_DATA     *SenseData,
2311   IN   UINTN                   NumberOfSenseKeys,
2312   OUT  UINTN                   *Action
2313   )
2314 {
2315   BOOLEAN RetryLater;
2316 
2317   //
2318   // Default is to read capacity, unless..
2319   //
2320   *Action = ACTION_READ_CAPACITY;
2321 
2322   if (NumberOfSenseKeys == 0) {
2323     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2324       *Action = ACTION_NO_ACTION;
2325     }
2326     return EFI_SUCCESS;
2327   }
2328 
2329   if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
2330     //
2331     // No Sense Key returned from last submitted command
2332     //
2333     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2334       *Action = ACTION_NO_ACTION;
2335     }
2336     return EFI_SUCCESS;
2337   }
2338 
2339   if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
2340     ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
2341     ScsiDiskDevice->BlkIo.Media->LastBlock    = 0;
2342     *Action = ACTION_NO_ACTION;
2343     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2344     return EFI_SUCCESS;
2345   }
2346 
2347   if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
2348     ScsiDiskDevice->BlkIo.Media->MediaId++;
2349     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2350     return EFI_SUCCESS;
2351   }
2352 
2353   if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
2354     *Action = ACTION_RETRY_COMMAND_LATER;
2355     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2356     return EFI_SUCCESS;
2357   }
2358 
2359   if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
2360     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
2361     *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2362     return EFI_DEVICE_ERROR;
2363   }
2364 
2365   if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
2366     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2367     *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2368     return EFI_DEVICE_ERROR;
2369   }
2370 
2371   if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
2372     if (RetryLater) {
2373       *Action = ACTION_RETRY_COMMAND_LATER;
2374       DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2375       return EFI_SUCCESS;
2376     }
2377     *Action = ACTION_NO_ACTION;
2378     return EFI_DEVICE_ERROR;
2379   }
2380 
2381   *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2382   DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
2383   return EFI_SUCCESS;
2384 }
2385 
2386 
2387 /**
2388   Send read capacity command to device and get the device parameter.
2389 
2390   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
2391   @param  NeedRetry          The pointer of flag indicates if need a retry
2392   @param  SenseDataArray     The pointer of an array of sense data
2393   @param  NumberOfSenseKeys  The number of sense key
2394 
2395   @retval EFI_DEVICE_ERROR   Indicates that error occurs
2396   @retval EFI_SUCCESS        Successfully to read capacity or sense data is received.
2397 
2398 **/
2399 EFI_STATUS
ScsiDiskReadCapacity(IN OUT SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry,OUT EFI_SCSI_SENSE_DATA ** SenseDataArray,OUT UINTN * NumberOfSenseKeys)2400 ScsiDiskReadCapacity (
2401   IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
2402       OUT  BOOLEAN                 *NeedRetry,
2403       OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,
2404       OUT  UINTN                   *NumberOfSenseKeys
2405   )
2406 {
2407   UINT8                         HostAdapterStatus;
2408   UINT8                         TargetStatus;
2409   EFI_STATUS                    CommandStatus;
2410   EFI_STATUS                    Status;
2411   UINT8                         Index;
2412   UINT8                         MaxRetry;
2413   UINT8                         SenseDataLength;
2414   UINT32                        DataLength10;
2415   UINT32                        DataLength16;
2416   EFI_SCSI_DISK_CAPACITY_DATA   *CapacityData10;
2417   EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
2418 
2419   CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2420   if (CapacityData10 == NULL) {
2421     *NeedRetry = FALSE;
2422     return EFI_DEVICE_ERROR;
2423   }
2424   CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
2425   if (CapacityData16 == NULL) {
2426     FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2427     *NeedRetry = FALSE;
2428     return EFI_DEVICE_ERROR;
2429   }
2430 
2431   SenseDataLength       = 0;
2432   DataLength10          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
2433   DataLength16          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
2434   ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2435   ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
2436 
2437   *NumberOfSenseKeys  = 0;
2438   *NeedRetry          = FALSE;
2439 
2440   //
2441   // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
2442   // 16 byte command should be used to access large hard disk >2TB
2443   //
2444   CommandStatus = ScsiReadCapacityCommand (
2445                     ScsiDiskDevice->ScsiIo,
2446                     SCSI_DISK_TIMEOUT,
2447                     NULL,
2448                     &SenseDataLength,
2449                     &HostAdapterStatus,
2450                     &TargetStatus,
2451                     (VOID *) CapacityData10,
2452                     &DataLength10,
2453                     FALSE
2454                     );
2455 
2456   ScsiDiskDevice->Cdb16Byte = FALSE;
2457   if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
2458       (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
2459     //
2460     // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
2461     //
2462     ScsiDiskDevice->Cdb16Byte = TRUE;
2463     //
2464     // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
2465     // and LowestAlignedLba
2466     //
2467     CommandStatus = ScsiReadCapacity16Command (
2468                       ScsiDiskDevice->ScsiIo,
2469                       SCSI_DISK_TIMEOUT,
2470                       NULL,
2471                       &SenseDataLength,
2472                       &HostAdapterStatus,
2473                       &TargetStatus,
2474                       (VOID *) CapacityData16,
2475                       &DataLength16,
2476                       FALSE
2477                       );
2478   }
2479 
2480     //
2481     // no need to check HostAdapterStatus and TargetStatus
2482     //
2483    if (CommandStatus == EFI_SUCCESS) {
2484      GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
2485      FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2486      FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
2487      return EFI_SUCCESS;
2488    }
2489 
2490    FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2491    FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
2492 
2493    if (CommandStatus == EFI_NOT_READY) {
2494      *NeedRetry = TRUE;
2495      return EFI_DEVICE_ERROR;
2496    } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
2497      *NeedRetry = FALSE;
2498      return EFI_DEVICE_ERROR;
2499    }
2500 
2501    //
2502    // go ahead to check HostAdapterStatus and TargetStatus
2503    // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2504    //
2505 
2506    Status = CheckHostAdapterStatus (HostAdapterStatus);
2507    if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2508      *NeedRetry = TRUE;
2509      return EFI_DEVICE_ERROR;
2510 
2511    } else if (Status == EFI_DEVICE_ERROR) {
2512     //
2513     // reset the scsi channel
2514     //
2515     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2516     *NeedRetry = FALSE;
2517     return EFI_DEVICE_ERROR;
2518   }
2519 
2520   Status = CheckTargetStatus (TargetStatus);
2521   if (Status == EFI_NOT_READY) {
2522     //
2523     // reset the scsi device
2524     //
2525     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2526     *NeedRetry = TRUE;
2527     return EFI_DEVICE_ERROR;
2528 
2529   } else if (Status == EFI_DEVICE_ERROR) {
2530     *NeedRetry = FALSE;
2531     return EFI_DEVICE_ERROR;
2532   }
2533 
2534   //
2535   // if goes here, meant ScsiReadCapacityCommand() failed.
2536   // if ScsiDiskRequestSenseKeys() succeeds at last,
2537   // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
2538   //
2539   MaxRetry = 3;
2540   for (Index = 0; Index < MaxRetry; Index++) {
2541 
2542     Status = ScsiDiskRequestSenseKeys (
2543               ScsiDiskDevice,
2544               NeedRetry,
2545               SenseDataArray,
2546               NumberOfSenseKeys,
2547               TRUE
2548               );
2549     if (!EFI_ERROR (Status)) {
2550       return EFI_SUCCESS;
2551     }
2552 
2553     if (!*NeedRetry) {
2554       return EFI_DEVICE_ERROR;
2555     }
2556   }
2557   //
2558   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2559   // set *NeedRetry = FALSE to avoid the outside caller try again.
2560   //
2561   *NeedRetry = FALSE;
2562   return EFI_DEVICE_ERROR;
2563 }
2564 
2565 /**
2566   Check the HostAdapter status and re-interpret it in EFI_STATUS.
2567 
2568   @param  HostAdapterStatus  Host Adapter status
2569 
2570   @retval  EFI_SUCCESS       Host adapter is OK.
2571   @retval  EFI_TIMEOUT       Timeout.
2572   @retval  EFI_NOT_READY     Adapter NOT ready.
2573   @retval  EFI_DEVICE_ERROR  Adapter device error.
2574 
2575 **/
2576 EFI_STATUS
CheckHostAdapterStatus(IN UINT8 HostAdapterStatus)2577 CheckHostAdapterStatus (
2578   IN UINT8   HostAdapterStatus
2579   )
2580 {
2581   switch (HostAdapterStatus) {
2582   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
2583     return EFI_SUCCESS;
2584 
2585   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
2586   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
2587   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
2588     return EFI_TIMEOUT;
2589 
2590   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
2591   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
2592   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
2593   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
2594   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
2595     return EFI_NOT_READY;
2596 
2597   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
2598   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
2599     return EFI_DEVICE_ERROR;
2600 
2601   default:
2602     return EFI_SUCCESS;
2603   }
2604 }
2605 
2606 
2607 /**
2608   Check the target status and re-interpret it in EFI_STATUS.
2609 
2610   @param  TargetStatus  Target status
2611 
2612   @retval EFI_NOT_READY       Device is NOT ready.
2613   @retval EFI_DEVICE_ERROR
2614   @retval EFI_SUCCESS
2615 
2616 **/
2617 EFI_STATUS
CheckTargetStatus(IN UINT8 TargetStatus)2618 CheckTargetStatus (
2619   IN  UINT8   TargetStatus
2620   )
2621 {
2622   switch (TargetStatus) {
2623   case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
2624   case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
2625   case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
2626     return EFI_SUCCESS;
2627 
2628   case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
2629   case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
2630   case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
2631   case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
2632     return EFI_NOT_READY;
2633 
2634   case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
2635     return EFI_DEVICE_ERROR;
2636 
2637   default:
2638     return EFI_SUCCESS;
2639   }
2640 }
2641 
2642 
2643 /**
2644   Retrieve all sense keys from the device.
2645 
2646   When encountering error during the process, if retrieve sense keys before
2647   error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2648   and NeedRetry set to FALSE; otherwize, return the proper return status.
2649 
2650   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
2651   @param  NeedRetry          The pointer of flag indicates if need a retry
2652   @param  SenseDataArray     The pointer of an array of sense data
2653   @param  NumberOfSenseKeys  The number of sense key
2654   @param  AskResetIfError    The flag indicates if need reset when error occurs
2655 
2656   @retval EFI_DEVICE_ERROR   Indicates that error occurs
2657   @retval EFI_SUCCESS        Successfully to request sense key
2658 
2659 **/
2660 EFI_STATUS
ScsiDiskRequestSenseKeys(IN OUT SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry,OUT EFI_SCSI_SENSE_DATA ** SenseDataArray,OUT UINTN * NumberOfSenseKeys,IN BOOLEAN AskResetIfError)2661 ScsiDiskRequestSenseKeys (
2662   IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
2663       OUT  BOOLEAN                 *NeedRetry,
2664       OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,
2665       OUT  UINTN                   *NumberOfSenseKeys,
2666   IN       BOOLEAN                 AskResetIfError
2667   )
2668 {
2669   EFI_SCSI_SENSE_DATA *PtrSenseData;
2670   UINT8               SenseDataLength;
2671   BOOLEAN             SenseReq;
2672   EFI_STATUS          Status;
2673   EFI_STATUS          FallStatus;
2674   UINT8               HostAdapterStatus;
2675   UINT8               TargetStatus;
2676 
2677   FallStatus      = EFI_SUCCESS;
2678   SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
2679 
2680   ZeroMem (
2681     ScsiDiskDevice->SenseData,
2682     sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
2683     );
2684 
2685   *NumberOfSenseKeys  = 0;
2686   *SenseDataArray     = ScsiDiskDevice->SenseData;
2687   Status              = EFI_SUCCESS;
2688   PtrSenseData        = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
2689   if (PtrSenseData == NULL) {
2690     return EFI_DEVICE_ERROR;
2691   }
2692 
2693   for (SenseReq = TRUE; SenseReq;) {
2694     ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
2695     Status = ScsiRequestSenseCommand (
2696               ScsiDiskDevice->ScsiIo,
2697               SCSI_DISK_TIMEOUT,
2698               PtrSenseData,
2699               &SenseDataLength,
2700               &HostAdapterStatus,
2701               &TargetStatus
2702               );
2703      if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
2704         FallStatus = EFI_SUCCESS;
2705 
2706      } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2707        *NeedRetry  = TRUE;
2708        FallStatus  = EFI_DEVICE_ERROR;
2709 
2710      } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2711        *NeedRetry  = FALSE;
2712        FallStatus  = EFI_DEVICE_ERROR;
2713 
2714      } else if (Status == EFI_DEVICE_ERROR) {
2715         if (AskResetIfError) {
2716           ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2717         }
2718 
2719         FallStatus = EFI_DEVICE_ERROR;
2720     }
2721 
2722     if (EFI_ERROR (FallStatus)) {
2723       if (*NumberOfSenseKeys != 0) {
2724         *NeedRetry = FALSE;
2725         Status = EFI_SUCCESS;
2726         goto EXIT;
2727       } else {
2728         Status = EFI_DEVICE_ERROR;
2729         goto EXIT;
2730       }
2731     }
2732 
2733     CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
2734     (*NumberOfSenseKeys) += 1;
2735 
2736     //
2737     // no more sense key or number of sense keys exceeds predefined,
2738     // skip the loop.
2739     //
2740     if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
2741         (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
2742       SenseReq = FALSE;
2743     }
2744   }
2745 
2746 EXIT:
2747   FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
2748   return Status;
2749 }
2750 
2751 
2752 /**
2753   Get information from media read capacity command.
2754 
2755   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
2756   @param  Capacity10      The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2757   @param  Capacity16      The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2758 
2759 **/
2760 VOID
GetMediaInfo(IN OUT SCSI_DISK_DEV * ScsiDiskDevice,IN EFI_SCSI_DISK_CAPACITY_DATA * Capacity10,IN EFI_SCSI_DISK_CAPACITY_DATA16 * Capacity16)2761 GetMediaInfo (
2762   IN OUT SCSI_DISK_DEV                  *ScsiDiskDevice,
2763   IN     EFI_SCSI_DISK_CAPACITY_DATA    *Capacity10,
2764   IN     EFI_SCSI_DISK_CAPACITY_DATA16  *Capacity16
2765   )
2766 {
2767   UINT8       *Ptr;
2768 
2769   if (!ScsiDiskDevice->Cdb16Byte) {
2770     ScsiDiskDevice->BlkIo.Media->LastBlock =  ((UINT32) Capacity10->LastLba3 << 24) |
2771                                               (Capacity10->LastLba2 << 16) |
2772                                               (Capacity10->LastLba1 << 8)  |
2773                                                Capacity10->LastLba0;
2774 
2775     ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
2776                                              (Capacity10->BlockSize2 << 16) |
2777                                              (Capacity10->BlockSize1 << 8)  |
2778                                               Capacity10->BlockSize0;
2779     ScsiDiskDevice->BlkIo.Media->LowestAlignedLba               = 0;
2780     ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = 0;
2781     if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
2782       ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) ScsiDiskDevice->BlkIo.Media->LastBlock;
2783     }
2784   } else {
2785     Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
2786     *Ptr++ = Capacity16->LastLba0;
2787     *Ptr++ = Capacity16->LastLba1;
2788     *Ptr++ = Capacity16->LastLba2;
2789     *Ptr++ = Capacity16->LastLba3;
2790     *Ptr++ = Capacity16->LastLba4;
2791     *Ptr++ = Capacity16->LastLba5;
2792     *Ptr++ = Capacity16->LastLba6;
2793     *Ptr   = Capacity16->LastLba7;
2794 
2795     ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
2796                                              (Capacity16->BlockSize2 << 16) |
2797                                              (Capacity16->BlockSize1 << 8)  |
2798                                               Capacity16->BlockSize0;
2799 
2800     ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
2801                                                      Capacity16->LowestAlignLogic1;
2802     ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = (1 << Capacity16->LogicPerPhysical);
2803     if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
2804       if (ScsiDiskDevice->BlkIo.Media->LastBlock > (UINT32) -1) {
2805         ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) -1;
2806       } else {
2807         ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) ScsiDiskDevice->BlkIo.Media->LastBlock;
2808       }
2809     }
2810   }
2811 
2812   ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
2813 }
2814 
2815 /**
2816   Parse Inquiry data.
2817 
2818   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
2819 
2820 **/
2821 VOID
ParseInquiryData(IN OUT SCSI_DISK_DEV * ScsiDiskDevice)2822 ParseInquiryData (
2823   IN OUT SCSI_DISK_DEV   *ScsiDiskDevice
2824   )
2825 {
2826   ScsiDiskDevice->FixedDevice               = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
2827   ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
2828 }
2829 
2830 /**
2831   Read sector from SCSI Disk.
2832 
2833   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
2834   @param  Buffer          The buffer to fill in the read out data
2835   @param  Lba             Logic block address
2836   @param  NumberOfBlocks  The number of blocks to read
2837 
2838   @retval EFI_DEVICE_ERROR  Indicates a device error.
2839   @retval EFI_SUCCESS       Operation is successful.
2840 
2841 **/
2842 EFI_STATUS
ScsiDiskReadSectors(IN SCSI_DISK_DEV * ScsiDiskDevice,OUT VOID * Buffer,IN EFI_LBA Lba,IN UINTN NumberOfBlocks)2843 ScsiDiskReadSectors (
2844   IN   SCSI_DISK_DEV     *ScsiDiskDevice,
2845   OUT  VOID              *Buffer,
2846   IN   EFI_LBA           Lba,
2847   IN   UINTN             NumberOfBlocks
2848   )
2849 {
2850   UINTN               BlocksRemaining;
2851   UINT8               *PtrBuffer;
2852   UINT32              BlockSize;
2853   UINT32              ByteCount;
2854   UINT32              MaxBlock;
2855   UINT32              SectorCount;
2856   UINT32              NextSectorCount;
2857   UINT64              Timeout;
2858   EFI_STATUS          Status;
2859   UINT8               Index;
2860   UINT8               MaxRetry;
2861   BOOLEAN             NeedRetry;
2862 
2863   Status            = EFI_SUCCESS;
2864 
2865   BlocksRemaining   = NumberOfBlocks;
2866   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
2867 
2868   //
2869   // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2870   //
2871   if (!ScsiDiskDevice->Cdb16Byte) {
2872     MaxBlock         = 0xFFFF;
2873   } else {
2874     MaxBlock         = 0xFFFFFFFF;
2875   }
2876 
2877   PtrBuffer = Buffer;
2878 
2879   while (BlocksRemaining > 0) {
2880 
2881     if (BlocksRemaining <= MaxBlock) {
2882       if (!ScsiDiskDevice->Cdb16Byte) {
2883         SectorCount = (UINT16) BlocksRemaining;
2884       } else {
2885         SectorCount = (UINT32) BlocksRemaining;
2886       }
2887     } else {
2888       SectorCount = MaxBlock;
2889     }
2890 
2891     ByteCount = SectorCount * BlockSize;
2892     //
2893     // |------------------------|-----------------|------------------|-----------------|
2894     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
2895     // |------------------------|-----------------|------------------|-----------------|
2896     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
2897     // |------------------------|-----------------|------------------|-----------------|
2898     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
2899     // |------------------------|-----------------|------------------|-----------------|
2900     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
2901     // |------------------------|-----------------|------------------|-----------------|
2902     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
2903     // |------------------------|-----------------|------------------|-----------------|
2904     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
2905     // |------------------------|-----------------|------------------|-----------------|
2906     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
2907     // |------------------------|-----------------|------------------|-----------------|
2908     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
2909     // |------------------------|-----------------|------------------|-----------------|
2910     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
2911     // |------------------------|-----------------|------------------|-----------------|
2912     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
2913     // |------------------------|-----------------|------------------|-----------------|
2914     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
2915     // |------------------------|-----------------|------------------|-----------------|
2916     //
2917     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2918     // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2919     // From the above table, we could know 2.1Mbytes per second is lowest one.
2920     // The timout value is rounded up to nearest integar and here an additional 30s is added
2921     // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2922     // commands in the Standby/Idle mode.
2923     //
2924     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2925 
2926     MaxRetry  = 2;
2927     for (Index = 0; Index < MaxRetry; Index++) {
2928       if (!ScsiDiskDevice->Cdb16Byte) {
2929         Status = ScsiDiskRead10 (
2930                   ScsiDiskDevice,
2931                   &NeedRetry,
2932                   Timeout,
2933                   PtrBuffer,
2934                   &ByteCount,
2935                   (UINT32) Lba,
2936                   SectorCount
2937                   );
2938       } else {
2939         Status = ScsiDiskRead16 (
2940                   ScsiDiskDevice,
2941                   &NeedRetry,
2942                   Timeout,
2943                   PtrBuffer,
2944                   &ByteCount,
2945                   Lba,
2946                   SectorCount
2947                   );
2948       }
2949       if (!EFI_ERROR (Status)) {
2950         break;
2951       }
2952 
2953       if (!NeedRetry) {
2954         return EFI_DEVICE_ERROR;
2955       }
2956 
2957       //
2958       // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2959       // lowered ByteCount on output, we must make sure that we lower
2960       // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2961       // it is invalid to request more sectors in the CDB than the entire
2962       // transfer (ie. ByteCount) can carry.
2963       //
2964       // In addition, ByteCount is only expected to go down, or stay unchaged.
2965       // Therefore we don't need to update Timeout: the original timeout should
2966       // accommodate shorter transfers too.
2967       //
2968       NextSectorCount = ByteCount / BlockSize;
2969       if (NextSectorCount < SectorCount) {
2970         SectorCount = NextSectorCount;
2971         //
2972         // Account for any rounding down.
2973         //
2974         ByteCount = SectorCount * BlockSize;
2975       }
2976     }
2977 
2978     if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
2979       return EFI_DEVICE_ERROR;
2980     }
2981 
2982     //
2983     // actual transferred sectors
2984     //
2985     SectorCount = ByteCount / BlockSize;
2986 
2987     Lba += SectorCount;
2988     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2989     BlocksRemaining -= SectorCount;
2990   }
2991 
2992   return EFI_SUCCESS;
2993 }
2994 
2995 /**
2996   Write sector to SCSI Disk.
2997 
2998   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
2999   @param  Buffer          The buffer of data to be written into SCSI Disk
3000   @param  Lba             Logic block address
3001   @param  NumberOfBlocks  The number of blocks to read
3002 
3003   @retval EFI_DEVICE_ERROR  Indicates a device error.
3004   @retval EFI_SUCCESS       Operation is successful.
3005 
3006 **/
3007 EFI_STATUS
ScsiDiskWriteSectors(IN SCSI_DISK_DEV * ScsiDiskDevice,IN VOID * Buffer,IN EFI_LBA Lba,IN UINTN NumberOfBlocks)3008 ScsiDiskWriteSectors (
3009   IN  SCSI_DISK_DEV     *ScsiDiskDevice,
3010   IN  VOID              *Buffer,
3011   IN  EFI_LBA           Lba,
3012   IN  UINTN             NumberOfBlocks
3013   )
3014 {
3015   UINTN               BlocksRemaining;
3016   UINT8               *PtrBuffer;
3017   UINT32              BlockSize;
3018   UINT32              ByteCount;
3019   UINT32              MaxBlock;
3020   UINT32              SectorCount;
3021   UINT32              NextSectorCount;
3022   UINT64              Timeout;
3023   EFI_STATUS          Status;
3024   UINT8               Index;
3025   UINT8               MaxRetry;
3026   BOOLEAN             NeedRetry;
3027 
3028   Status            = EFI_SUCCESS;
3029 
3030   BlocksRemaining   = NumberOfBlocks;
3031   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
3032 
3033   //
3034   // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3035   //
3036   if (!ScsiDiskDevice->Cdb16Byte) {
3037     MaxBlock         = 0xFFFF;
3038   } else {
3039     MaxBlock         = 0xFFFFFFFF;
3040   }
3041 
3042   PtrBuffer = Buffer;
3043 
3044   while (BlocksRemaining > 0) {
3045 
3046     if (BlocksRemaining <= MaxBlock) {
3047       if (!ScsiDiskDevice->Cdb16Byte) {
3048         SectorCount = (UINT16) BlocksRemaining;
3049       } else {
3050         SectorCount = (UINT32) BlocksRemaining;
3051       }
3052     } else {
3053       SectorCount = MaxBlock;
3054     }
3055 
3056     ByteCount = SectorCount * BlockSize;
3057     //
3058     // |------------------------|-----------------|------------------|-----------------|
3059     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
3060     // |------------------------|-----------------|------------------|-----------------|
3061     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
3062     // |------------------------|-----------------|------------------|-----------------|
3063     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
3064     // |------------------------|-----------------|------------------|-----------------|
3065     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
3066     // |------------------------|-----------------|------------------|-----------------|
3067     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
3068     // |------------------------|-----------------|------------------|-----------------|
3069     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
3070     // |------------------------|-----------------|------------------|-----------------|
3071     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
3072     // |------------------------|-----------------|------------------|-----------------|
3073     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
3074     // |------------------------|-----------------|------------------|-----------------|
3075     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
3076     // |------------------------|-----------------|------------------|-----------------|
3077     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
3078     // |------------------------|-----------------|------------------|-----------------|
3079     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
3080     // |------------------------|-----------------|------------------|-----------------|
3081     //
3082     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3083     // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3084     // From the above table, we could know 2.1Mbytes per second is lowest one.
3085     // The timout value is rounded up to nearest integar and here an additional 30s is added
3086     // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3087     // commands in the Standby/Idle mode.
3088     //
3089     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3090     MaxRetry  = 2;
3091     for (Index = 0; Index < MaxRetry; Index++) {
3092       if (!ScsiDiskDevice->Cdb16Byte) {
3093         Status = ScsiDiskWrite10 (
3094                   ScsiDiskDevice,
3095                   &NeedRetry,
3096                   Timeout,
3097                   PtrBuffer,
3098                   &ByteCount,
3099                   (UINT32) Lba,
3100                   SectorCount
3101                   );
3102       } else {
3103         Status = ScsiDiskWrite16 (
3104                   ScsiDiskDevice,
3105                   &NeedRetry,
3106                   Timeout,
3107                   PtrBuffer,
3108                   &ByteCount,
3109                   Lba,
3110                   SectorCount
3111                   );
3112         }
3113       if (!EFI_ERROR (Status)) {
3114         break;
3115       }
3116 
3117       if (!NeedRetry) {
3118         return EFI_DEVICE_ERROR;
3119       }
3120 
3121       //
3122       // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3123       // has lowered ByteCount on output, we must make sure that we lower
3124       // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3125       // it is invalid to request more sectors in the CDB than the entire
3126       // transfer (ie. ByteCount) can carry.
3127       //
3128       // In addition, ByteCount is only expected to go down, or stay unchaged.
3129       // Therefore we don't need to update Timeout: the original timeout should
3130       // accommodate shorter transfers too.
3131       //
3132       NextSectorCount = ByteCount / BlockSize;
3133       if (NextSectorCount < SectorCount) {
3134         SectorCount = NextSectorCount;
3135         //
3136         // Account for any rounding down.
3137         //
3138         ByteCount = SectorCount * BlockSize;
3139       }
3140     }
3141 
3142     if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
3143       return EFI_DEVICE_ERROR;
3144     }
3145     //
3146     // actual transferred sectors
3147     //
3148     SectorCount = ByteCount / BlockSize;
3149 
3150     Lba += SectorCount;
3151     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3152     BlocksRemaining -= SectorCount;
3153   }
3154 
3155   return EFI_SUCCESS;
3156 }
3157 
3158 /**
3159   Asynchronously read sector from SCSI Disk.
3160 
3161   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
3162   @param  Buffer          The buffer to fill in the read out data.
3163   @param  Lba             Logic block address.
3164   @param  NumberOfBlocks  The number of blocks to read.
3165   @param  Token           A pointer to the token associated with the
3166                           non-blocking read request.
3167 
3168   @retval EFI_INVALID_PARAMETER  Token is NULL or Token->Event is NULL.
3169   @retval EFI_DEVICE_ERROR       Indicates a device error.
3170   @retval EFI_SUCCESS            Operation is successful.
3171 
3172 **/
3173 EFI_STATUS
ScsiDiskAsyncReadSectors(IN SCSI_DISK_DEV * ScsiDiskDevice,OUT VOID * Buffer,IN EFI_LBA Lba,IN UINTN NumberOfBlocks,IN EFI_BLOCK_IO2_TOKEN * Token)3174 ScsiDiskAsyncReadSectors (
3175   IN   SCSI_DISK_DEV         *ScsiDiskDevice,
3176   OUT  VOID                  *Buffer,
3177   IN   EFI_LBA               Lba,
3178   IN   UINTN                 NumberOfBlocks,
3179   IN   EFI_BLOCK_IO2_TOKEN   *Token
3180   )
3181 {
3182   UINTN                 BlocksRemaining;
3183   UINT8                 *PtrBuffer;
3184   UINT32                BlockSize;
3185   UINT32                ByteCount;
3186   UINT32                MaxBlock;
3187   UINT32                SectorCount;
3188   UINT64                Timeout;
3189   SCSI_BLKIO2_REQUEST   *BlkIo2Req;
3190   EFI_STATUS            Status;
3191   EFI_TPL               OldTpl;
3192 
3193   if ((Token == NULL) || (Token->Event == NULL)) {
3194     return EFI_INVALID_PARAMETER;
3195   }
3196 
3197   BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
3198   if (BlkIo2Req == NULL) {
3199     return EFI_OUT_OF_RESOURCES;
3200   }
3201 
3202   BlkIo2Req->Token  = Token;
3203 
3204   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3205   InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
3206   gBS->RestoreTPL (OldTpl);
3207 
3208   InitializeListHead (&BlkIo2Req->ScsiRWQueue);
3209 
3210   Status            = EFI_SUCCESS;
3211 
3212   BlocksRemaining   = NumberOfBlocks;
3213   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
3214 
3215   //
3216   // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3217   // Command
3218   //
3219   if (!ScsiDiskDevice->Cdb16Byte) {
3220     MaxBlock         = 0xFFFF;
3221   } else {
3222     MaxBlock         = 0xFFFFFFFF;
3223   }
3224 
3225   PtrBuffer = Buffer;
3226 
3227   while (BlocksRemaining > 0) {
3228 
3229     if (BlocksRemaining <= MaxBlock) {
3230       if (!ScsiDiskDevice->Cdb16Byte) {
3231         SectorCount = (UINT16) BlocksRemaining;
3232       } else {
3233         SectorCount = (UINT32) BlocksRemaining;
3234       }
3235     } else {
3236       SectorCount = MaxBlock;
3237     }
3238 
3239     ByteCount = SectorCount * BlockSize;
3240     //
3241     // |------------------------|-----------------|------------------|-----------------|
3242     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
3243     // |------------------------|-----------------|------------------|-----------------|
3244     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
3245     // |------------------------|-----------------|------------------|-----------------|
3246     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
3247     // |------------------------|-----------------|------------------|-----------------|
3248     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
3249     // |------------------------|-----------------|------------------|-----------------|
3250     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
3251     // |------------------------|-----------------|------------------|-----------------|
3252     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
3253     // |------------------------|-----------------|------------------|-----------------|
3254     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
3255     // |------------------------|-----------------|------------------|-----------------|
3256     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
3257     // |------------------------|-----------------|------------------|-----------------|
3258     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
3259     // |------------------------|-----------------|------------------|-----------------|
3260     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
3261     // |------------------------|-----------------|------------------|-----------------|
3262     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
3263     // |------------------------|-----------------|------------------|-----------------|
3264     //
3265     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3266     // we have to use the lowest transfer rate to calculate the possible
3267     // maximum timeout value for each operation.
3268     // From the above table, we could know 2.1Mbytes per second is lowest one.
3269     // The timout value is rounded up to nearest integar and here an additional
3270     // 30s is added to follow ATA spec in which it mentioned that the device
3271     // may take up to 30s to respond commands in the Standby/Idle mode.
3272     //
3273     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3274 
3275     if (!ScsiDiskDevice->Cdb16Byte) {
3276       Status = ScsiDiskAsyncRead10 (
3277                  ScsiDiskDevice,
3278                  Timeout,
3279                  0,
3280                  PtrBuffer,
3281                  ByteCount,
3282                  (UINT32) Lba,
3283                  SectorCount,
3284                  BlkIo2Req,
3285                  Token
3286                  );
3287     } else {
3288       Status = ScsiDiskAsyncRead16 (
3289                  ScsiDiskDevice,
3290                  Timeout,
3291                  0,
3292                  PtrBuffer,
3293                  ByteCount,
3294                  Lba,
3295                  SectorCount,
3296                  BlkIo2Req,
3297                  Token
3298                  );
3299     }
3300     if (EFI_ERROR (Status)) {
3301       //
3302       // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3303       // length of a SCSI I/O command is too large.
3304       // In this case, we retry sending the SCSI command with a data length
3305       // half of its previous value.
3306       //
3307       if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
3308         if ((MaxBlock > 1) && (SectorCount > 1)) {
3309           MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
3310           continue;
3311         }
3312       }
3313 
3314       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3315       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3316         //
3317         // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3318         // SCSI sub-task running. Otherwise, it will be freed in the callback
3319         // function ScsiDiskNotify().
3320         //
3321         RemoveEntryList (&BlkIo2Req->Link);
3322         FreePool (BlkIo2Req);
3323         BlkIo2Req = NULL;
3324         gBS->RestoreTPL (OldTpl);
3325 
3326         //
3327         // It is safe to return error status to the caller, since there is no
3328         // previous SCSI sub-task executing.
3329         //
3330         Status = EFI_DEVICE_ERROR;
3331         goto Done;
3332       } else {
3333         gBS->RestoreTPL (OldTpl);
3334 
3335         //
3336         // There are previous SCSI commands still running, EFI_SUCCESS should
3337         // be returned to make sure that the caller does not free resources
3338         // still using by these SCSI commands.
3339         //
3340         Status = EFI_SUCCESS;
3341         goto Done;
3342       }
3343     }
3344 
3345     //
3346     // Sectors submitted for transfer
3347     //
3348     SectorCount = ByteCount / BlockSize;
3349 
3350     Lba += SectorCount;
3351     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3352     BlocksRemaining -= SectorCount;
3353   }
3354 
3355   Status = EFI_SUCCESS;
3356 
3357 Done:
3358   if (BlkIo2Req != NULL) {
3359     BlkIo2Req->LastScsiRW = TRUE;
3360 
3361     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3362     if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3363       RemoveEntryList (&BlkIo2Req->Link);
3364       FreePool (BlkIo2Req);
3365       BlkIo2Req = NULL;
3366 
3367       gBS->SignalEvent (Token->Event);
3368     }
3369     gBS->RestoreTPL (OldTpl);
3370   }
3371 
3372   return Status;
3373 }
3374 
3375 /**
3376   Asynchronously write sector to SCSI Disk.
3377 
3378   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
3379   @param  Buffer          The buffer of data to be written into SCSI Disk.
3380   @param  Lba             Logic block address.
3381   @param  NumberOfBlocks  The number of blocks to read.
3382   @param  Token           A pointer to the token associated with the
3383                           non-blocking read request.
3384 
3385   @retval EFI_INVALID_PARAMETER  Token is NULL or Token->Event is NULL
3386   @retval EFI_DEVICE_ERROR  Indicates a device error.
3387   @retval EFI_SUCCESS       Operation is successful.
3388 
3389 **/
3390 EFI_STATUS
ScsiDiskAsyncWriteSectors(IN SCSI_DISK_DEV * ScsiDiskDevice,IN VOID * Buffer,IN EFI_LBA Lba,IN UINTN NumberOfBlocks,IN EFI_BLOCK_IO2_TOKEN * Token)3391 ScsiDiskAsyncWriteSectors (
3392   IN  SCSI_DISK_DEV          *ScsiDiskDevice,
3393   IN  VOID                   *Buffer,
3394   IN  EFI_LBA                Lba,
3395   IN  UINTN                  NumberOfBlocks,
3396   IN  EFI_BLOCK_IO2_TOKEN    *Token
3397   )
3398 {
3399   UINTN                 BlocksRemaining;
3400   UINT8                 *PtrBuffer;
3401   UINT32                BlockSize;
3402   UINT32                ByteCount;
3403   UINT32                MaxBlock;
3404   UINT32                SectorCount;
3405   UINT64                Timeout;
3406   SCSI_BLKIO2_REQUEST   *BlkIo2Req;
3407   EFI_STATUS            Status;
3408   EFI_TPL               OldTpl;
3409 
3410   if ((Token == NULL) || (Token->Event == NULL)) {
3411     return EFI_INVALID_PARAMETER;
3412   }
3413 
3414   BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
3415   if (BlkIo2Req == NULL) {
3416     return EFI_OUT_OF_RESOURCES;
3417   }
3418 
3419   BlkIo2Req->Token  = Token;
3420 
3421   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3422   InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
3423   gBS->RestoreTPL (OldTpl);
3424 
3425   InitializeListHead (&BlkIo2Req->ScsiRWQueue);
3426 
3427   Status            = EFI_SUCCESS;
3428 
3429   BlocksRemaining   = NumberOfBlocks;
3430   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
3431 
3432   //
3433   // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3434   // Command
3435   //
3436   if (!ScsiDiskDevice->Cdb16Byte) {
3437     MaxBlock         = 0xFFFF;
3438   } else {
3439     MaxBlock         = 0xFFFFFFFF;
3440   }
3441 
3442   PtrBuffer = Buffer;
3443 
3444   while (BlocksRemaining > 0) {
3445 
3446     if (BlocksRemaining <= MaxBlock) {
3447       if (!ScsiDiskDevice->Cdb16Byte) {
3448         SectorCount = (UINT16) BlocksRemaining;
3449       } else {
3450         SectorCount = (UINT32) BlocksRemaining;
3451       }
3452     } else {
3453       SectorCount = MaxBlock;
3454     }
3455 
3456     ByteCount = SectorCount * BlockSize;
3457     //
3458     // |------------------------|-----------------|------------------|-----------------|
3459     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
3460     // |------------------------|-----------------|------------------|-----------------|
3461     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
3462     // |------------------------|-----------------|------------------|-----------------|
3463     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
3464     // |------------------------|-----------------|------------------|-----------------|
3465     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
3466     // |------------------------|-----------------|------------------|-----------------|
3467     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
3468     // |------------------------|-----------------|------------------|-----------------|
3469     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
3470     // |------------------------|-----------------|------------------|-----------------|
3471     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
3472     // |------------------------|-----------------|------------------|-----------------|
3473     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
3474     // |------------------------|-----------------|------------------|-----------------|
3475     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
3476     // |------------------------|-----------------|------------------|-----------------|
3477     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
3478     // |------------------------|-----------------|------------------|-----------------|
3479     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
3480     // |------------------------|-----------------|------------------|-----------------|
3481     //
3482     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3483     // we have to use the lowest transfer rate to calculate the possible
3484     // maximum timeout value for each operation.
3485     // From the above table, we could know 2.1Mbytes per second is lowest one.
3486     // The timout value is rounded up to nearest integar and here an additional
3487     // 30s is added to follow ATA spec in which it mentioned that the device
3488     // may take up to 30s to respond commands in the Standby/Idle mode.
3489     //
3490     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3491 
3492     if (!ScsiDiskDevice->Cdb16Byte) {
3493       Status = ScsiDiskAsyncWrite10 (
3494                  ScsiDiskDevice,
3495                  Timeout,
3496                  0,
3497                  PtrBuffer,
3498                  ByteCount,
3499                  (UINT32) Lba,
3500                  SectorCount,
3501                  BlkIo2Req,
3502                  Token
3503                  );
3504     } else {
3505       Status = ScsiDiskAsyncWrite16 (
3506                  ScsiDiskDevice,
3507                  Timeout,
3508                  0,
3509                  PtrBuffer,
3510                  ByteCount,
3511                  Lba,
3512                  SectorCount,
3513                  BlkIo2Req,
3514                  Token
3515                  );
3516     }
3517     if (EFI_ERROR (Status)) {
3518       //
3519       // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3520       // length of a SCSI I/O command is too large.
3521       // In this case, we retry sending the SCSI command with a data length
3522       // half of its previous value.
3523       //
3524       if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
3525         if ((MaxBlock > 1) && (SectorCount > 1)) {
3526           MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
3527           continue;
3528         }
3529       }
3530 
3531       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3532       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3533         //
3534         // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3535         // SCSI sub-task running. Otherwise, it will be freed in the callback
3536         // function ScsiDiskNotify().
3537         //
3538         RemoveEntryList (&BlkIo2Req->Link);
3539         FreePool (BlkIo2Req);
3540         BlkIo2Req = NULL;
3541         gBS->RestoreTPL (OldTpl);
3542 
3543         //
3544         // It is safe to return error status to the caller, since there is no
3545         // previous SCSI sub-task executing.
3546         //
3547         Status = EFI_DEVICE_ERROR;
3548         goto Done;
3549       } else {
3550         gBS->RestoreTPL (OldTpl);
3551 
3552         //
3553         // There are previous SCSI commands still running, EFI_SUCCESS should
3554         // be returned to make sure that the caller does not free resources
3555         // still using by these SCSI commands.
3556         //
3557         Status = EFI_SUCCESS;
3558         goto Done;
3559       }
3560     }
3561 
3562     //
3563     // Sectors submitted for transfer
3564     //
3565     SectorCount = ByteCount / BlockSize;
3566 
3567     Lba += SectorCount;
3568     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3569     BlocksRemaining -= SectorCount;
3570   }
3571 
3572   Status = EFI_SUCCESS;
3573 
3574 Done:
3575   if (BlkIo2Req != NULL) {
3576     BlkIo2Req->LastScsiRW = TRUE;
3577 
3578     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3579     if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3580       RemoveEntryList (&BlkIo2Req->Link);
3581       FreePool (BlkIo2Req);
3582       BlkIo2Req = NULL;
3583 
3584       gBS->SignalEvent (Token->Event);
3585     }
3586     gBS->RestoreTPL (OldTpl);
3587   }
3588 
3589   return Status;
3590 }
3591 
3592 
3593 /**
3594   Submit Read(10) command.
3595 
3596   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
3597   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
3598   @param  Timeout            The time to complete the command
3599   @param  DataBuffer         The buffer to fill with the read out data
3600   @param  DataLength         The length of buffer
3601   @param  StartLba           The start logic block address
3602   @param  SectorCount        The number of blocks to read
3603 
3604   @return  EFI_STATUS is returned by calling ScsiRead10Command().
3605 **/
3606 EFI_STATUS
ScsiDiskRead10(IN SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry,IN UINT64 Timeout,OUT UINT8 * DataBuffer,IN OUT UINT32 * DataLength,IN UINT32 StartLba,IN UINT32 SectorCount)3607 ScsiDiskRead10 (
3608   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
3609      OUT BOOLEAN               *NeedRetry,
3610   IN     UINT64                Timeout,
3611      OUT UINT8                 *DataBuffer,
3612   IN OUT UINT32                *DataLength,
3613   IN     UINT32                StartLba,
3614   IN     UINT32                SectorCount
3615   )
3616 {
3617   UINT8       SenseDataLength;
3618   EFI_STATUS  Status;
3619   EFI_STATUS  ReturnStatus;
3620   UINT8       HostAdapterStatus;
3621   UINT8       TargetStatus;
3622   UINTN       Action;
3623 
3624   //
3625   // Implement a backoff algorithem to resolve some compatibility issues that
3626   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3627   // big data in a single operation.
3628   // This algorithem will at first try to execute original request. If the request fails
3629   // with media error sense data or else, it will reduce the transfer length to half and
3630   // try again till the operation succeeds or fails with one sector transfer length.
3631   //
3632 BackOff:
3633   *NeedRetry          = FALSE;
3634   Action              = ACTION_NO_ACTION;
3635   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3636   ReturnStatus = ScsiRead10Command (
3637                    ScsiDiskDevice->ScsiIo,
3638                    Timeout,
3639                    ScsiDiskDevice->SenseData,
3640                    &SenseDataLength,
3641                    &HostAdapterStatus,
3642                    &TargetStatus,
3643                    DataBuffer,
3644                    DataLength,
3645                    StartLba,
3646                    SectorCount
3647                    );
3648 
3649   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3650     *NeedRetry = TRUE;
3651     return EFI_DEVICE_ERROR;
3652   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3653     *NeedRetry = FALSE;
3654     return ReturnStatus;
3655   }
3656 
3657   //
3658   // go ahead to check HostAdapterStatus and TargetStatus
3659   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3660   //
3661   Status = CheckHostAdapterStatus (HostAdapterStatus);
3662   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3663     *NeedRetry = TRUE;
3664     return EFI_DEVICE_ERROR;
3665   } else if (Status == EFI_DEVICE_ERROR) {
3666     //
3667     // reset the scsi channel
3668     //
3669     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3670     *NeedRetry = FALSE;
3671     return EFI_DEVICE_ERROR;
3672   }
3673 
3674   Status = CheckTargetStatus (TargetStatus);
3675   if (Status == EFI_NOT_READY) {
3676     //
3677     // reset the scsi device
3678     //
3679     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3680     *NeedRetry = TRUE;
3681     return EFI_DEVICE_ERROR;
3682   } else if (Status == EFI_DEVICE_ERROR) {
3683     *NeedRetry = FALSE;
3684     return EFI_DEVICE_ERROR;
3685   }
3686 
3687   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3688     DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
3689     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3690     if (Action == ACTION_RETRY_COMMAND_LATER) {
3691       *NeedRetry = TRUE;
3692       return EFI_DEVICE_ERROR;
3693     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3694       if (SectorCount <= 1) {
3695         //
3696         // Jump out if the operation still fails with one sector transfer length.
3697         //
3698         *NeedRetry = FALSE;
3699         return EFI_DEVICE_ERROR;
3700       }
3701       //
3702       // Try again with half length if the sense data shows we need to retry.
3703       //
3704       SectorCount >>= 1;
3705       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3706       goto BackOff;
3707     } else {
3708       *NeedRetry = FALSE;
3709       return EFI_DEVICE_ERROR;
3710     }
3711   }
3712 
3713   return ReturnStatus;
3714 }
3715 
3716 
3717 /**
3718   Submit Write(10) Command.
3719 
3720   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
3721   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
3722   @param  Timeout            The time to complete the command
3723   @param  DataBuffer         The buffer to fill with the read out data
3724   @param  DataLength         The length of buffer
3725   @param  StartLba           The start logic block address
3726   @param  SectorCount        The number of blocks to write
3727 
3728   @return  EFI_STATUS is returned by calling ScsiWrite10Command().
3729 
3730 **/
3731 EFI_STATUS
ScsiDiskWrite10(IN SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry,IN UINT64 Timeout,IN UINT8 * DataBuffer,IN OUT UINT32 * DataLength,IN UINT32 StartLba,IN UINT32 SectorCount)3732 ScsiDiskWrite10 (
3733   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
3734      OUT BOOLEAN               *NeedRetry,
3735   IN     UINT64                Timeout,
3736   IN     UINT8                 *DataBuffer,
3737   IN OUT UINT32                *DataLength,
3738   IN     UINT32                StartLba,
3739   IN     UINT32                SectorCount
3740   )
3741 {
3742   EFI_STATUS  Status;
3743   EFI_STATUS  ReturnStatus;
3744   UINT8       SenseDataLength;
3745   UINT8       HostAdapterStatus;
3746   UINT8       TargetStatus;
3747   UINTN       Action;
3748 
3749   //
3750   // Implement a backoff algorithem to resolve some compatibility issues that
3751   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3752   // big data in a single operation.
3753   // This algorithem will at first try to execute original request. If the request fails
3754   // with media error sense data or else, it will reduce the transfer length to half and
3755   // try again till the operation succeeds or fails with one sector transfer length.
3756   //
3757 BackOff:
3758   *NeedRetry          = FALSE;
3759   Action              = ACTION_NO_ACTION;
3760   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3761   ReturnStatus = ScsiWrite10Command (
3762                    ScsiDiskDevice->ScsiIo,
3763                    Timeout,
3764                    ScsiDiskDevice->SenseData,
3765                    &SenseDataLength,
3766                    &HostAdapterStatus,
3767                    &TargetStatus,
3768                    DataBuffer,
3769                    DataLength,
3770                    StartLba,
3771                    SectorCount
3772                    );
3773   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3774     *NeedRetry = TRUE;
3775     return EFI_DEVICE_ERROR;
3776   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3777     *NeedRetry = FALSE;
3778     return ReturnStatus;
3779   }
3780 
3781   //
3782   // go ahead to check HostAdapterStatus and TargetStatus
3783   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3784   //
3785   Status = CheckHostAdapterStatus (HostAdapterStatus);
3786   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3787     *NeedRetry = TRUE;
3788     return EFI_DEVICE_ERROR;
3789   } else if (Status == EFI_DEVICE_ERROR) {
3790     //
3791     // reset the scsi channel
3792     //
3793     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3794     *NeedRetry = FALSE;
3795     return EFI_DEVICE_ERROR;
3796   }
3797 
3798   Status = CheckTargetStatus (TargetStatus);
3799   if (Status == EFI_NOT_READY) {
3800     //
3801     // reset the scsi device
3802     //
3803     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3804     *NeedRetry = TRUE;
3805     return EFI_DEVICE_ERROR;
3806   } else if (Status == EFI_DEVICE_ERROR) {
3807     *NeedRetry = FALSE;
3808     return EFI_DEVICE_ERROR;
3809   }
3810 
3811   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3812     DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
3813     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3814     if (Action == ACTION_RETRY_COMMAND_LATER) {
3815       *NeedRetry = TRUE;
3816       return EFI_DEVICE_ERROR;
3817     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3818       if (SectorCount <= 1) {
3819         //
3820         // Jump out if the operation still fails with one sector transfer length.
3821         //
3822         *NeedRetry = FALSE;
3823         return EFI_DEVICE_ERROR;
3824       }
3825       //
3826       // Try again with half length if the sense data shows we need to retry.
3827       //
3828       SectorCount >>= 1;
3829       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3830       goto BackOff;
3831     } else {
3832       *NeedRetry = FALSE;
3833       return EFI_DEVICE_ERROR;
3834     }
3835   }
3836 
3837   return ReturnStatus;
3838 }
3839 
3840 
3841 /**
3842   Submit Read(16) command.
3843 
3844   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
3845   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
3846   @param  Timeout            The time to complete the command
3847   @param  DataBuffer         The buffer to fill with the read out data
3848   @param  DataLength         The length of buffer
3849   @param  StartLba           The start logic block address
3850   @param  SectorCount        The number of blocks to read
3851 
3852   @return  EFI_STATUS is returned by calling ScsiRead16Command().
3853 **/
3854 EFI_STATUS
ScsiDiskRead16(IN SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry,IN UINT64 Timeout,OUT UINT8 * DataBuffer,IN OUT UINT32 * DataLength,IN UINT64 StartLba,IN UINT32 SectorCount)3855 ScsiDiskRead16 (
3856   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
3857      OUT BOOLEAN               *NeedRetry,
3858   IN     UINT64                Timeout,
3859      OUT UINT8                 *DataBuffer,
3860   IN OUT UINT32                *DataLength,
3861   IN     UINT64                StartLba,
3862   IN     UINT32                SectorCount
3863   )
3864 {
3865   UINT8       SenseDataLength;
3866   EFI_STATUS  Status;
3867   EFI_STATUS  ReturnStatus;
3868   UINT8       HostAdapterStatus;
3869   UINT8       TargetStatus;
3870   UINTN       Action;
3871 
3872   //
3873   // Implement a backoff algorithem to resolve some compatibility issues that
3874   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3875   // big data in a single operation.
3876   // This algorithem will at first try to execute original request. If the request fails
3877   // with media error sense data or else, it will reduce the transfer length to half and
3878   // try again till the operation succeeds or fails with one sector transfer length.
3879   //
3880 BackOff:
3881   *NeedRetry          = FALSE;
3882   Action              = ACTION_NO_ACTION;
3883   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3884   ReturnStatus = ScsiRead16Command (
3885                    ScsiDiskDevice->ScsiIo,
3886                    Timeout,
3887                    ScsiDiskDevice->SenseData,
3888                    &SenseDataLength,
3889                    &HostAdapterStatus,
3890                    &TargetStatus,
3891                    DataBuffer,
3892                    DataLength,
3893                    StartLba,
3894                    SectorCount
3895                    );
3896   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3897     *NeedRetry = TRUE;
3898     return EFI_DEVICE_ERROR;
3899   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3900     *NeedRetry = FALSE;
3901     return ReturnStatus;
3902   }
3903 
3904   //
3905   // go ahead to check HostAdapterStatus and TargetStatus
3906   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3907   //
3908   Status = CheckHostAdapterStatus (HostAdapterStatus);
3909   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3910     *NeedRetry = TRUE;
3911     return EFI_DEVICE_ERROR;
3912   } else if (Status == EFI_DEVICE_ERROR) {
3913     //
3914     // reset the scsi channel
3915     //
3916     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3917     *NeedRetry = FALSE;
3918     return EFI_DEVICE_ERROR;
3919   }
3920 
3921   Status = CheckTargetStatus (TargetStatus);
3922   if (Status == EFI_NOT_READY) {
3923     //
3924     // reset the scsi device
3925     //
3926     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3927     *NeedRetry = TRUE;
3928     return EFI_DEVICE_ERROR;
3929   } else if (Status == EFI_DEVICE_ERROR) {
3930     *NeedRetry = FALSE;
3931     return EFI_DEVICE_ERROR;
3932   }
3933 
3934   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3935     DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
3936     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3937     if (Action == ACTION_RETRY_COMMAND_LATER) {
3938       *NeedRetry = TRUE;
3939       return EFI_DEVICE_ERROR;
3940     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3941       if (SectorCount <= 1) {
3942         //
3943         // Jump out if the operation still fails with one sector transfer length.
3944         //
3945         *NeedRetry = FALSE;
3946         return EFI_DEVICE_ERROR;
3947       }
3948       //
3949       // Try again with half length if the sense data shows we need to retry.
3950       //
3951       SectorCount >>= 1;
3952       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3953       goto BackOff;
3954     } else {
3955       *NeedRetry = FALSE;
3956       return EFI_DEVICE_ERROR;
3957     }
3958   }
3959 
3960   return ReturnStatus;
3961 }
3962 
3963 
3964 /**
3965   Submit Write(16) Command.
3966 
3967   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
3968   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
3969   @param  Timeout            The time to complete the command
3970   @param  DataBuffer         The buffer to fill with the read out data
3971   @param  DataLength         The length of buffer
3972   @param  StartLba           The start logic block address
3973   @param  SectorCount        The number of blocks to write
3974 
3975   @return  EFI_STATUS is returned by calling ScsiWrite16Command().
3976 
3977 **/
3978 EFI_STATUS
ScsiDiskWrite16(IN SCSI_DISK_DEV * ScsiDiskDevice,OUT BOOLEAN * NeedRetry,IN UINT64 Timeout,IN UINT8 * DataBuffer,IN OUT UINT32 * DataLength,IN UINT64 StartLba,IN UINT32 SectorCount)3979 ScsiDiskWrite16 (
3980   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
3981      OUT BOOLEAN               *NeedRetry,
3982   IN     UINT64                Timeout,
3983   IN     UINT8                 *DataBuffer,
3984   IN OUT UINT32                *DataLength,
3985   IN     UINT64                StartLba,
3986   IN     UINT32                SectorCount
3987   )
3988 {
3989   EFI_STATUS  Status;
3990   EFI_STATUS  ReturnStatus;
3991   UINT8       SenseDataLength;
3992   UINT8       HostAdapterStatus;
3993   UINT8       TargetStatus;
3994   UINTN       Action;
3995 
3996   //
3997   // Implement a backoff algorithem to resolve some compatibility issues that
3998   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3999   // big data in a single operation.
4000   // This algorithem will at first try to execute original request. If the request fails
4001   // with media error sense data or else, it will reduce the transfer length to half and
4002   // try again till the operation succeeds or fails with one sector transfer length.
4003   //
4004 BackOff:
4005   *NeedRetry          = FALSE;
4006   Action              = ACTION_NO_ACTION;
4007   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4008   ReturnStatus = ScsiWrite16Command (
4009                    ScsiDiskDevice->ScsiIo,
4010                    Timeout,
4011                    ScsiDiskDevice->SenseData,
4012                    &SenseDataLength,
4013                    &HostAdapterStatus,
4014                    &TargetStatus,
4015                    DataBuffer,
4016                    DataLength,
4017                    StartLba,
4018                    SectorCount
4019                    );
4020   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
4021     *NeedRetry = TRUE;
4022     return EFI_DEVICE_ERROR;
4023   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4024     *NeedRetry = FALSE;
4025     return ReturnStatus;
4026   }
4027 
4028   //
4029   // go ahead to check HostAdapterStatus and TargetStatus
4030   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4031   //
4032   Status = CheckHostAdapterStatus (HostAdapterStatus);
4033   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4034     *NeedRetry = TRUE;
4035     return EFI_DEVICE_ERROR;
4036   } else if (Status == EFI_DEVICE_ERROR) {
4037     //
4038     // reset the scsi channel
4039     //
4040     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4041     *NeedRetry = FALSE;
4042     return EFI_DEVICE_ERROR;
4043   }
4044 
4045   Status = CheckTargetStatus (TargetStatus);
4046   if (Status == EFI_NOT_READY) {
4047     //
4048     // reset the scsi device
4049     //
4050     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4051     *NeedRetry = TRUE;
4052     return EFI_DEVICE_ERROR;
4053   } else if (Status == EFI_DEVICE_ERROR) {
4054     *NeedRetry = FALSE;
4055     return EFI_DEVICE_ERROR;
4056   }
4057 
4058   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4059     DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
4060     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4061     if (Action == ACTION_RETRY_COMMAND_LATER) {
4062       *NeedRetry = TRUE;
4063       return EFI_DEVICE_ERROR;
4064     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4065       if (SectorCount <= 1) {
4066         //
4067         // Jump out if the operation still fails with one sector transfer length.
4068         //
4069         *NeedRetry = FALSE;
4070         return EFI_DEVICE_ERROR;
4071       }
4072       //
4073       // Try again with half length if the sense data shows we need to retry.
4074       //
4075       SectorCount >>= 1;
4076       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4077       goto BackOff;
4078     } else {
4079       *NeedRetry = FALSE;
4080       return EFI_DEVICE_ERROR;
4081     }
4082   }
4083 
4084   return ReturnStatus;
4085 }
4086 
4087 
4088 /**
4089   Internal helper notify function in which determine whether retry of a SCSI
4090   Read/Write command is needed and signal the event passed from Block I/O(2) if
4091   the SCSI I/O operation completes.
4092 
4093   @param  Event    The instance of EFI_EVENT.
4094   @param  Context  The parameter passed in.
4095 
4096 **/
4097 VOID
4098 EFIAPI
ScsiDiskNotify(IN EFI_EVENT Event,IN VOID * Context)4099 ScsiDiskNotify (
4100   IN  EFI_EVENT  Event,
4101   IN  VOID       *Context
4102   )
4103 {
4104   EFI_STATUS                       Status;
4105   SCSI_ASYNC_RW_REQUEST            *Request;
4106   SCSI_DISK_DEV                    *ScsiDiskDevice;
4107   EFI_BLOCK_IO2_TOKEN              *Token;
4108   UINTN                            Action;
4109   UINT32                           OldDataLength;
4110   UINT32                           OldSectorCount;
4111   UINT8                            MaxRetry;
4112 
4113   gBS->CloseEvent (Event);
4114 
4115   Request         = (SCSI_ASYNC_RW_REQUEST *) Context;
4116   ScsiDiskDevice  = Request->ScsiDiskDevice;
4117   Token           = Request->BlkIo2Req->Token;
4118   OldDataLength   = Request->DataLength;
4119   OldSectorCount  = Request->SectorCount;
4120   MaxRetry        = 2;
4121 
4122   //
4123   // If previous sub-tasks already fails, no need to process this sub-task.
4124   //
4125   if (Token->TransactionStatus != EFI_SUCCESS) {
4126     goto Exit;
4127   }
4128 
4129   //
4130   // Check HostAdapterStatus and TargetStatus
4131   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4132   //
4133   Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
4134   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4135     if (++Request->TimesRetry > MaxRetry) {
4136       Token->TransactionStatus = EFI_DEVICE_ERROR;
4137       goto Exit;
4138     } else {
4139       goto Retry;
4140     }
4141   } else if (Status == EFI_DEVICE_ERROR) {
4142     //
4143     // reset the scsi channel
4144     //
4145     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4146     Token->TransactionStatus = EFI_DEVICE_ERROR;
4147     goto Exit;
4148   }
4149 
4150   Status = CheckTargetStatus (Request->TargetStatus);
4151   if (Status == EFI_NOT_READY) {
4152     //
4153     // reset the scsi device
4154     //
4155     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4156     if (++Request->TimesRetry > MaxRetry) {
4157       Token->TransactionStatus = EFI_DEVICE_ERROR;
4158       goto Exit;
4159     } else {
4160       goto Retry;
4161     }
4162   } else if (Status == EFI_DEVICE_ERROR) {
4163     Token->TransactionStatus = EFI_DEVICE_ERROR;
4164     goto Exit;
4165   }
4166 
4167   if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
4168     DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
4169 
4170     Status = DetectMediaParsingSenseKeys (
4171                ScsiDiskDevice,
4172                Request->SenseData,
4173                Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
4174                &Action
4175                );
4176     if (Action == ACTION_RETRY_COMMAND_LATER) {
4177       if (++Request->TimesRetry > MaxRetry) {
4178         Token->TransactionStatus = EFI_DEVICE_ERROR;
4179         goto Exit;
4180       } else {
4181         goto Retry;
4182       }
4183     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4184       if (Request->SectorCount <= 1) {
4185         //
4186         // Jump out if the operation still fails with one sector transfer
4187         // length.
4188         //
4189         Token->TransactionStatus = EFI_DEVICE_ERROR;
4190         goto Exit;
4191       }
4192       //
4193       // Try again with two half length request if the sense data shows we need
4194       // to retry.
4195       //
4196       Request->SectorCount >>= 1;
4197       Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4198       Request->TimesRetry  = 0;
4199 
4200       goto Retry;
4201     } else {
4202       Token->TransactionStatus = EFI_DEVICE_ERROR;
4203       goto Exit;
4204     }
4205   }
4206 
4207   //
4208   // This sub-task succeeds, no need to retry.
4209   //
4210   goto Exit;
4211 
4212 Retry:
4213   if (Request->InBuffer != NULL) {
4214     //
4215     // SCSI read command
4216     //
4217     if (!ScsiDiskDevice->Cdb16Byte) {
4218       Status = ScsiDiskAsyncRead10 (
4219                  ScsiDiskDevice,
4220                  Request->Timeout,
4221                  Request->TimesRetry,
4222                  Request->InBuffer,
4223                  Request->DataLength,
4224                  (UINT32) Request->StartLba,
4225                  Request->SectorCount,
4226                  Request->BlkIo2Req,
4227                  Token
4228                  );
4229     } else {
4230       Status = ScsiDiskAsyncRead16 (
4231                  ScsiDiskDevice,
4232                  Request->Timeout,
4233                  Request->TimesRetry,
4234                  Request->InBuffer,
4235                  Request->DataLength,
4236                  Request->StartLba,
4237                  Request->SectorCount,
4238                  Request->BlkIo2Req,
4239                  Token
4240                  );
4241     }
4242 
4243     if (EFI_ERROR (Status)) {
4244       Token->TransactionStatus = EFI_DEVICE_ERROR;
4245       goto Exit;
4246     } else if (OldSectorCount != Request->SectorCount) {
4247       //
4248       // Original sub-task will be split into two new sub-tasks with smaller
4249       // DataLength
4250       //
4251       if (!ScsiDiskDevice->Cdb16Byte) {
4252         Status = ScsiDiskAsyncRead10 (
4253                    ScsiDiskDevice,
4254                    Request->Timeout,
4255                    0,
4256                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4257                    OldDataLength - Request->DataLength,
4258                    (UINT32) Request->StartLba + Request->SectorCount,
4259                    OldSectorCount - Request->SectorCount,
4260                    Request->BlkIo2Req,
4261                    Token
4262                    );
4263       } else {
4264         Status = ScsiDiskAsyncRead16 (
4265                    ScsiDiskDevice,
4266                    Request->Timeout,
4267                    0,
4268                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4269                    OldDataLength - Request->DataLength,
4270                    Request->StartLba + Request->SectorCount,
4271                    OldSectorCount - Request->SectorCount,
4272                    Request->BlkIo2Req,
4273                    Token
4274                    );
4275       }
4276       if (EFI_ERROR (Status)) {
4277         Token->TransactionStatus = EFI_DEVICE_ERROR;
4278         goto Exit;
4279       }
4280     }
4281   } else {
4282     //
4283     // SCSI write command
4284     //
4285     if (!ScsiDiskDevice->Cdb16Byte) {
4286       Status = ScsiDiskAsyncWrite10 (
4287                  ScsiDiskDevice,
4288                  Request->Timeout,
4289                  Request->TimesRetry,
4290                  Request->OutBuffer,
4291                  Request->DataLength,
4292                  (UINT32) Request->StartLba,
4293                  Request->SectorCount,
4294                  Request->BlkIo2Req,
4295                  Token
4296                  );
4297     } else {
4298       Status = ScsiDiskAsyncWrite16 (
4299                  ScsiDiskDevice,
4300                  Request->Timeout,
4301                  Request->TimesRetry,
4302                  Request->OutBuffer,
4303                  Request->DataLength,
4304                  Request->StartLba,
4305                  Request->SectorCount,
4306                  Request->BlkIo2Req,
4307                  Token
4308                  );
4309     }
4310 
4311     if (EFI_ERROR (Status)) {
4312       Token->TransactionStatus = EFI_DEVICE_ERROR;
4313       goto Exit;
4314     } else if (OldSectorCount != Request->SectorCount) {
4315       //
4316       // Original sub-task will be split into two new sub-tasks with smaller
4317       // DataLength
4318       //
4319       if (!ScsiDiskDevice->Cdb16Byte) {
4320         Status = ScsiDiskAsyncWrite10 (
4321                    ScsiDiskDevice,
4322                    Request->Timeout,
4323                    0,
4324                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4325                    OldDataLength - Request->DataLength,
4326                    (UINT32) Request->StartLba + Request->SectorCount,
4327                    OldSectorCount - Request->SectorCount,
4328                    Request->BlkIo2Req,
4329                    Token
4330                    );
4331       } else {
4332         Status = ScsiDiskAsyncWrite16 (
4333                    ScsiDiskDevice,
4334                    Request->Timeout,
4335                    0,
4336                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4337                    OldDataLength - Request->DataLength,
4338                    Request->StartLba + Request->SectorCount,
4339                    OldSectorCount - Request->SectorCount,
4340                    Request->BlkIo2Req,
4341                    Token
4342                    );
4343       }
4344       if (EFI_ERROR (Status)) {
4345         Token->TransactionStatus = EFI_DEVICE_ERROR;
4346         goto Exit;
4347       }
4348     }
4349   }
4350 
4351 Exit:
4352   RemoveEntryList (&Request->Link);
4353   if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
4354       (Request->BlkIo2Req->LastScsiRW)) {
4355     //
4356     // The last SCSI R/W command of a BlockIo2 request completes
4357     //
4358     RemoveEntryList (&Request->BlkIo2Req->Link);
4359     FreePool (Request->BlkIo2Req);  // Should be freed only once
4360     gBS->SignalEvent (Token->Event);
4361   }
4362 
4363   FreePool (Request->SenseData);
4364   FreePool (Request);
4365 }
4366 
4367 
4368 /**
4369   Submit Async Read(10) command.
4370 
4371   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
4372   @param  Timeout            The time to complete the command.
4373   @param  TimesRetry         The number of times the command has been retried.
4374   @param  DataBuffer         The buffer to fill with the read out data.
4375   @param  DataLength         The length of buffer.
4376   @param  StartLba           The start logic block address.
4377   @param  SectorCount        The number of blocks to read.
4378   @param  BlkIo2Req          The upstream BlockIo2 request.
4379   @param  Token              The pointer to the token associated with the
4380                              non-blocking read request.
4381 
4382   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
4383                                 lack of resources.
4384   @return others                Status returned by calling
4385                                 ScsiRead10CommandEx().
4386 
4387 **/
4388 EFI_STATUS
ScsiDiskAsyncRead10(IN SCSI_DISK_DEV * ScsiDiskDevice,IN UINT64 Timeout,IN UINT8 TimesRetry,OUT UINT8 * DataBuffer,IN UINT32 DataLength,IN UINT32 StartLba,IN UINT32 SectorCount,IN OUT SCSI_BLKIO2_REQUEST * BlkIo2Req,IN EFI_BLOCK_IO2_TOKEN * Token)4389 ScsiDiskAsyncRead10 (
4390   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4391   IN     UINT64                Timeout,
4392   IN     UINT8                 TimesRetry,
4393      OUT UINT8                 *DataBuffer,
4394   IN     UINT32                DataLength,
4395   IN     UINT32                StartLba,
4396   IN     UINT32                SectorCount,
4397   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
4398   IN     EFI_BLOCK_IO2_TOKEN   *Token
4399   )
4400 {
4401   EFI_STATUS                   Status;
4402   SCSI_ASYNC_RW_REQUEST        *Request;
4403   EFI_EVENT                    AsyncIoEvent;
4404   EFI_TPL                      OldTpl;
4405 
4406   AsyncIoEvent = NULL;
4407 
4408   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4409   if (Request == NULL) {
4410     return EFI_OUT_OF_RESOURCES;
4411   }
4412 
4413   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4414   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4415   gBS->RestoreTPL (OldTpl);
4416 
4417   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4418   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
4419   if (Request->SenseData == NULL) {
4420     Status = EFI_OUT_OF_RESOURCES;
4421     goto ErrorExit;
4422   }
4423 
4424   Request->ScsiDiskDevice  = ScsiDiskDevice;
4425   Request->Timeout         = Timeout;
4426   Request->TimesRetry      = TimesRetry;
4427   Request->InBuffer        = DataBuffer;
4428   Request->DataLength      = DataLength;
4429   Request->StartLba        = StartLba;
4430   Request->SectorCount     = SectorCount;
4431   Request->BlkIo2Req       = BlkIo2Req;
4432 
4433   //
4434   // Create Event
4435   //
4436   Status = gBS->CreateEvent (
4437                   EVT_NOTIFY_SIGNAL,
4438                   TPL_NOTIFY,
4439                   ScsiDiskNotify,
4440                   Request,
4441                   &AsyncIoEvent
4442                   );
4443   if (EFI_ERROR(Status)) {
4444     goto ErrorExit;
4445   }
4446 
4447   Status = ScsiRead10CommandEx (
4448              ScsiDiskDevice->ScsiIo,
4449              Request->Timeout,
4450              Request->SenseData,
4451              &Request->SenseDataLength,
4452              &Request->HostAdapterStatus,
4453              &Request->TargetStatus,
4454              Request->InBuffer,
4455              &Request->DataLength,
4456              (UINT32) Request->StartLba,
4457              Request->SectorCount,
4458              AsyncIoEvent
4459              );
4460   if (EFI_ERROR(Status)) {
4461     goto ErrorExit;
4462   }
4463 
4464   return EFI_SUCCESS;
4465 
4466 ErrorExit:
4467   if (AsyncIoEvent != NULL) {
4468     gBS->CloseEvent (AsyncIoEvent);
4469   }
4470 
4471   if (Request != NULL) {
4472     if (Request->SenseData != NULL) {
4473       FreePool (Request->SenseData);
4474     }
4475 
4476     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4477     RemoveEntryList (&Request->Link);
4478     gBS->RestoreTPL (OldTpl);
4479 
4480     FreePool (Request);
4481   }
4482 
4483   return Status;
4484 }
4485 
4486 
4487 /**
4488   Submit Async Write(10) command.
4489 
4490   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
4491   @param  Timeout            The time to complete the command.
4492   @param  TimesRetry         The number of times the command has been retried.
4493   @param  DataBuffer         The buffer contains the data to write.
4494   @param  DataLength         The length of buffer.
4495   @param  StartLba           The start logic block address.
4496   @param  SectorCount        The number of blocks to write.
4497   @param  BlkIo2Req          The upstream BlockIo2 request.
4498   @param  Token              The pointer to the token associated with the
4499                              non-blocking read request.
4500 
4501   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
4502                                 lack of resources.
4503   @return others                Status returned by calling
4504                                 ScsiWrite10CommandEx().
4505 
4506 **/
4507 EFI_STATUS
ScsiDiskAsyncWrite10(IN SCSI_DISK_DEV * ScsiDiskDevice,IN UINT64 Timeout,IN UINT8 TimesRetry,IN UINT8 * DataBuffer,IN UINT32 DataLength,IN UINT32 StartLba,IN UINT32 SectorCount,IN OUT SCSI_BLKIO2_REQUEST * BlkIo2Req,IN EFI_BLOCK_IO2_TOKEN * Token)4508 ScsiDiskAsyncWrite10 (
4509   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4510   IN     UINT64                Timeout,
4511   IN     UINT8                 TimesRetry,
4512   IN     UINT8                 *DataBuffer,
4513   IN     UINT32                DataLength,
4514   IN     UINT32                StartLba,
4515   IN     UINT32                SectorCount,
4516   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
4517   IN     EFI_BLOCK_IO2_TOKEN   *Token
4518   )
4519 {
4520   EFI_STATUS                   Status;
4521   SCSI_ASYNC_RW_REQUEST        *Request;
4522   EFI_EVENT                    AsyncIoEvent;
4523   EFI_TPL                      OldTpl;
4524 
4525   AsyncIoEvent = NULL;
4526 
4527   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4528   if (Request == NULL) {
4529     return EFI_OUT_OF_RESOURCES;
4530   }
4531 
4532   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4533   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4534   gBS->RestoreTPL (OldTpl);
4535 
4536   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4537   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
4538   if (Request->SenseData == NULL) {
4539     Status = EFI_OUT_OF_RESOURCES;
4540     goto ErrorExit;
4541   }
4542 
4543   Request->ScsiDiskDevice  = ScsiDiskDevice;
4544   Request->Timeout         = Timeout;
4545   Request->TimesRetry      = TimesRetry;
4546   Request->OutBuffer       = DataBuffer;
4547   Request->DataLength      = DataLength;
4548   Request->StartLba        = StartLba;
4549   Request->SectorCount     = SectorCount;
4550   Request->BlkIo2Req       = BlkIo2Req;
4551 
4552   //
4553   // Create Event
4554   //
4555   Status = gBS->CreateEvent (
4556                   EVT_NOTIFY_SIGNAL,
4557                   TPL_NOTIFY,
4558                   ScsiDiskNotify,
4559                   Request,
4560                   &AsyncIoEvent
4561                   );
4562   if (EFI_ERROR(Status)) {
4563     goto ErrorExit;
4564   }
4565 
4566   Status = ScsiWrite10CommandEx (
4567              ScsiDiskDevice->ScsiIo,
4568              Request->Timeout,
4569              Request->SenseData,
4570              &Request->SenseDataLength,
4571              &Request->HostAdapterStatus,
4572              &Request->TargetStatus,
4573              Request->OutBuffer,
4574              &Request->DataLength,
4575              (UINT32) Request->StartLba,
4576              Request->SectorCount,
4577              AsyncIoEvent
4578              );
4579   if (EFI_ERROR(Status)) {
4580     goto ErrorExit;
4581   }
4582 
4583   return EFI_SUCCESS;
4584 
4585 ErrorExit:
4586   if (AsyncIoEvent != NULL) {
4587     gBS->CloseEvent (AsyncIoEvent);
4588   }
4589 
4590   if (Request != NULL) {
4591     if (Request->SenseData != NULL) {
4592       FreePool (Request->SenseData);
4593     }
4594 
4595     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4596     RemoveEntryList (&Request->Link);
4597     gBS->RestoreTPL (OldTpl);
4598 
4599     FreePool (Request);
4600   }
4601 
4602   return Status;
4603 }
4604 
4605 
4606 /**
4607   Submit Async Read(16) command.
4608 
4609   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
4610   @param  Timeout            The time to complete the command.
4611   @param  TimesRetry         The number of times the command has been retried.
4612   @param  DataBuffer         The buffer to fill with the read out data.
4613   @param  DataLength         The length of buffer.
4614   @param  StartLba           The start logic block address.
4615   @param  SectorCount        The number of blocks to read.
4616   @param  BlkIo2Req          The upstream BlockIo2 request.
4617   @param  Token              The pointer to the token associated with the
4618                              non-blocking read request.
4619 
4620   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
4621                                 lack of resources.
4622   @return others                Status returned by calling
4623                                 ScsiRead16CommandEx().
4624 
4625 **/
4626 EFI_STATUS
ScsiDiskAsyncRead16(IN SCSI_DISK_DEV * ScsiDiskDevice,IN UINT64 Timeout,IN UINT8 TimesRetry,OUT UINT8 * DataBuffer,IN UINT32 DataLength,IN UINT64 StartLba,IN UINT32 SectorCount,IN OUT SCSI_BLKIO2_REQUEST * BlkIo2Req,IN EFI_BLOCK_IO2_TOKEN * Token)4627 ScsiDiskAsyncRead16 (
4628   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4629   IN     UINT64                Timeout,
4630   IN     UINT8                 TimesRetry,
4631      OUT UINT8                 *DataBuffer,
4632   IN     UINT32                DataLength,
4633   IN     UINT64                StartLba,
4634   IN     UINT32                SectorCount,
4635   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
4636   IN     EFI_BLOCK_IO2_TOKEN   *Token
4637   )
4638 {
4639   EFI_STATUS                   Status;
4640   SCSI_ASYNC_RW_REQUEST        *Request;
4641   EFI_EVENT                    AsyncIoEvent;
4642   EFI_TPL                      OldTpl;
4643 
4644   AsyncIoEvent = NULL;
4645 
4646   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4647   if (Request == NULL) {
4648     return EFI_OUT_OF_RESOURCES;
4649   }
4650 
4651   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4652   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4653   gBS->RestoreTPL (OldTpl);
4654 
4655   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4656   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
4657   if (Request->SenseData == NULL) {
4658     Status = EFI_OUT_OF_RESOURCES;
4659     goto ErrorExit;
4660   }
4661 
4662   Request->ScsiDiskDevice  = ScsiDiskDevice;
4663   Request->Timeout         = Timeout;
4664   Request->TimesRetry      = TimesRetry;
4665   Request->InBuffer        = DataBuffer;
4666   Request->DataLength      = DataLength;
4667   Request->StartLba        = StartLba;
4668   Request->SectorCount     = SectorCount;
4669   Request->BlkIo2Req       = BlkIo2Req;
4670 
4671   //
4672   // Create Event
4673   //
4674   Status = gBS->CreateEvent (
4675                   EVT_NOTIFY_SIGNAL,
4676                   TPL_NOTIFY,
4677                   ScsiDiskNotify,
4678                   Request,
4679                   &AsyncIoEvent
4680                   );
4681   if (EFI_ERROR(Status)) {
4682     goto ErrorExit;
4683   }
4684 
4685   Status = ScsiRead16CommandEx (
4686              ScsiDiskDevice->ScsiIo,
4687              Request->Timeout,
4688              Request->SenseData,
4689              &Request->SenseDataLength,
4690              &Request->HostAdapterStatus,
4691              &Request->TargetStatus,
4692              Request->InBuffer,
4693              &Request->DataLength,
4694              Request->StartLba,
4695              Request->SectorCount,
4696              AsyncIoEvent
4697              );
4698   if (EFI_ERROR(Status)) {
4699     goto ErrorExit;
4700   }
4701 
4702   return EFI_SUCCESS;
4703 
4704 ErrorExit:
4705   if (AsyncIoEvent != NULL) {
4706     gBS->CloseEvent (AsyncIoEvent);
4707   }
4708 
4709   if (Request != NULL) {
4710     if (Request->SenseData != NULL) {
4711       FreePool (Request->SenseData);
4712     }
4713 
4714     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4715     RemoveEntryList (&Request->Link);
4716     gBS->RestoreTPL (OldTpl);
4717 
4718     FreePool (Request);
4719   }
4720 
4721   return Status;
4722 }
4723 
4724 
4725 /**
4726   Submit Async Write(16) command.
4727 
4728   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
4729   @param  Timeout            The time to complete the command.
4730   @param  TimesRetry         The number of times the command has been retried.
4731   @param  DataBuffer         The buffer contains the data to write.
4732   @param  DataLength         The length of buffer.
4733   @param  StartLba           The start logic block address.
4734   @param  SectorCount        The number of blocks to write.
4735   @param  BlkIo2Req          The upstream BlockIo2 request.
4736   @param  Token              The pointer to the token associated with the
4737                              non-blocking read request.
4738 
4739   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
4740                                 lack of resources.
4741   @return others                Status returned by calling
4742                                 ScsiWrite16CommandEx().
4743 
4744 **/
4745 EFI_STATUS
ScsiDiskAsyncWrite16(IN SCSI_DISK_DEV * ScsiDiskDevice,IN UINT64 Timeout,IN UINT8 TimesRetry,IN UINT8 * DataBuffer,IN UINT32 DataLength,IN UINT64 StartLba,IN UINT32 SectorCount,IN OUT SCSI_BLKIO2_REQUEST * BlkIo2Req,IN EFI_BLOCK_IO2_TOKEN * Token)4746 ScsiDiskAsyncWrite16 (
4747   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4748   IN     UINT64                Timeout,
4749   IN     UINT8                 TimesRetry,
4750   IN     UINT8                 *DataBuffer,
4751   IN     UINT32                DataLength,
4752   IN     UINT64                StartLba,
4753   IN     UINT32                SectorCount,
4754   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
4755   IN     EFI_BLOCK_IO2_TOKEN   *Token
4756   )
4757 {
4758   EFI_STATUS                   Status;
4759   SCSI_ASYNC_RW_REQUEST        *Request;
4760   EFI_EVENT                    AsyncIoEvent;
4761   EFI_TPL                      OldTpl;
4762 
4763   AsyncIoEvent = NULL;
4764 
4765   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4766   if (Request == NULL) {
4767     return EFI_OUT_OF_RESOURCES;
4768   }
4769 
4770   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4771   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4772   gBS->RestoreTPL (OldTpl);
4773 
4774   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4775   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
4776   if (Request->SenseData == NULL) {
4777     Status = EFI_OUT_OF_RESOURCES;
4778     goto ErrorExit;
4779   }
4780 
4781   Request->ScsiDiskDevice  = ScsiDiskDevice;
4782   Request->Timeout         = Timeout;
4783   Request->TimesRetry      = TimesRetry;
4784   Request->OutBuffer       = DataBuffer;
4785   Request->DataLength      = DataLength;
4786   Request->StartLba        = StartLba;
4787   Request->SectorCount     = SectorCount;
4788   Request->BlkIo2Req       = BlkIo2Req;
4789 
4790   //
4791   // Create Event
4792   //
4793   Status = gBS->CreateEvent (
4794                   EVT_NOTIFY_SIGNAL,
4795                   TPL_NOTIFY,
4796                   ScsiDiskNotify,
4797                   Request,
4798                   &AsyncIoEvent
4799                   );
4800   if (EFI_ERROR(Status)) {
4801     goto ErrorExit;
4802   }
4803 
4804   Status = ScsiWrite16CommandEx (
4805              ScsiDiskDevice->ScsiIo,
4806              Request->Timeout,
4807              Request->SenseData,
4808              &Request->SenseDataLength,
4809              &Request->HostAdapterStatus,
4810              &Request->TargetStatus,
4811              Request->OutBuffer,
4812              &Request->DataLength,
4813              Request->StartLba,
4814              Request->SectorCount,
4815              AsyncIoEvent
4816              );
4817   if (EFI_ERROR(Status)) {
4818     goto ErrorExit;
4819   }
4820 
4821   return EFI_SUCCESS;
4822 
4823 ErrorExit:
4824   if (AsyncIoEvent != NULL) {
4825     gBS->CloseEvent (AsyncIoEvent);
4826   }
4827 
4828   if (Request != NULL) {
4829     if (Request->SenseData != NULL) {
4830       FreePool (Request->SenseData);
4831     }
4832 
4833     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4834     RemoveEntryList (&Request->Link);
4835     gBS->RestoreTPL (OldTpl);
4836 
4837     FreePool (Request);
4838   }
4839 
4840   return Status;
4841 }
4842 
4843 
4844 /**
4845   Check sense key to find if media presents.
4846 
4847   @param  SenseData   The pointer of EFI_SCSI_SENSE_DATA
4848   @param  SenseCounts The number of sense key
4849 
4850   @retval TRUE    NOT any media
4851   @retval FALSE   Media presents
4852 **/
4853 BOOLEAN
ScsiDiskIsNoMedia(IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN SenseCounts)4854 ScsiDiskIsNoMedia (
4855   IN  EFI_SCSI_SENSE_DATA   *SenseData,
4856   IN  UINTN                 SenseCounts
4857   )
4858 {
4859   EFI_SCSI_SENSE_DATA *SensePtr;
4860   UINTN               Index;
4861   BOOLEAN             IsNoMedia;
4862 
4863   IsNoMedia = FALSE;
4864   SensePtr  = SenseData;
4865 
4866   for (Index = 0; Index < SenseCounts; Index++) {
4867     //
4868     // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4869     // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4870     //
4871     if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
4872         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
4873       IsNoMedia = TRUE;
4874     }
4875     SensePtr++;
4876   }
4877 
4878   return IsNoMedia;
4879 }
4880 
4881 
4882 /**
4883   Parse sense key.
4884 
4885   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
4886   @param  SenseCounts  The number of sense key
4887 
4888   @retval TRUE   Error
4889   @retval FALSE  NOT error
4890 
4891 **/
4892 BOOLEAN
ScsiDiskIsMediaError(IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN SenseCounts)4893 ScsiDiskIsMediaError (
4894   IN  EFI_SCSI_SENSE_DATA   *SenseData,
4895   IN  UINTN                 SenseCounts
4896   )
4897 {
4898   EFI_SCSI_SENSE_DATA *SensePtr;
4899   UINTN               Index;
4900   BOOLEAN             IsError;
4901 
4902   IsError   = FALSE;
4903   SensePtr  = SenseData;
4904 
4905   for (Index = 0; Index < SenseCounts; Index++) {
4906 
4907     switch (SensePtr->Sense_Key) {
4908 
4909     case EFI_SCSI_SK_MEDIUM_ERROR:
4910       //
4911       // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4912       //
4913       switch (SensePtr->Addnl_Sense_Code) {
4914 
4915       //
4916       // fall through
4917       //
4918       case EFI_SCSI_ASC_MEDIA_ERR1:
4919 
4920       //
4921       // fall through
4922       //
4923       case EFI_SCSI_ASC_MEDIA_ERR2:
4924 
4925       //
4926       // fall through
4927       //
4928       case EFI_SCSI_ASC_MEDIA_ERR3:
4929       case EFI_SCSI_ASC_MEDIA_ERR4:
4930         IsError = TRUE;
4931         break;
4932 
4933       default:
4934         break;
4935       }
4936 
4937       break;
4938 
4939     case EFI_SCSI_SK_NOT_READY:
4940       //
4941       // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4942       //
4943       switch (SensePtr->Addnl_Sense_Code) {
4944       //
4945       // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4946       //
4947       case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
4948         IsError = TRUE;
4949         break;
4950 
4951       default:
4952         break;
4953       }
4954       break;
4955 
4956     default:
4957       break;
4958     }
4959 
4960     SensePtr++;
4961   }
4962 
4963   return IsError;
4964 }
4965 
4966 
4967 /**
4968   Check sense key to find if hardware error happens.
4969 
4970   @param  SenseData     The pointer of EFI_SCSI_SENSE_DATA
4971   @param  SenseCounts   The number of sense key
4972 
4973   @retval TRUE  Hardware error exits.
4974   @retval FALSE NO error.
4975 
4976 **/
4977 BOOLEAN
ScsiDiskIsHardwareError(IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN SenseCounts)4978 ScsiDiskIsHardwareError (
4979   IN  EFI_SCSI_SENSE_DATA   *SenseData,
4980   IN  UINTN                 SenseCounts
4981   )
4982 {
4983   EFI_SCSI_SENSE_DATA *SensePtr;
4984   UINTN               Index;
4985   BOOLEAN             IsError;
4986 
4987   IsError   = FALSE;
4988   SensePtr  = SenseData;
4989 
4990   for (Index = 0; Index < SenseCounts; Index++) {
4991 
4992     //
4993     // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4994     //
4995     if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
4996       IsError = TRUE;
4997     }
4998 
4999     SensePtr++;
5000   }
5001 
5002   return IsError;
5003 }
5004 
5005 
5006 /**
5007   Check sense key to find if media has changed.
5008 
5009   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
5010   @param  SenseCounts  The number of sense key
5011 
5012   @retval TRUE   Media is changed.
5013   @retval FALSE  Media is NOT changed.
5014 **/
5015 BOOLEAN
ScsiDiskIsMediaChange(IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN SenseCounts)5016 ScsiDiskIsMediaChange (
5017   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5018   IN  UINTN                 SenseCounts
5019   )
5020 {
5021   EFI_SCSI_SENSE_DATA *SensePtr;
5022   UINTN               Index;
5023   BOOLEAN             IsMediaChanged;
5024 
5025   IsMediaChanged  = FALSE;
5026   SensePtr        = SenseData;
5027 
5028   for (Index = 0; Index < SenseCounts; Index++) {
5029     //
5030     // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5031     // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5032     //
5033     if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5034         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
5035       IsMediaChanged = TRUE;
5036     }
5037 
5038     SensePtr++;
5039   }
5040 
5041   return IsMediaChanged;
5042 }
5043 
5044 /**
5045   Check sense key to find if reset happens.
5046 
5047   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
5048   @param  SenseCounts  The number of sense key
5049 
5050   @retval TRUE  It is reset before.
5051   @retval FALSE It is NOT reset before.
5052 
5053 **/
5054 BOOLEAN
ScsiDiskIsResetBefore(IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN SenseCounts)5055 ScsiDiskIsResetBefore (
5056   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5057   IN  UINTN                 SenseCounts
5058   )
5059 {
5060   EFI_SCSI_SENSE_DATA *SensePtr;
5061   UINTN               Index;
5062   BOOLEAN             IsResetBefore;
5063 
5064   IsResetBefore = FALSE;
5065   SensePtr      = SenseData;
5066 
5067   for (Index = 0; Index < SenseCounts; Index++) {
5068 
5069     //
5070     // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5071     // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5072     //
5073     if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5074         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
5075       IsResetBefore = TRUE;
5076     }
5077 
5078     SensePtr++;
5079   }
5080 
5081   return IsResetBefore;
5082 }
5083 
5084 /**
5085   Check sense key to find if the drive is ready.
5086 
5087   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
5088   @param  SenseCounts  The number of sense key
5089   @param  RetryLater   The flag means if need a retry
5090 
5091   @retval TRUE  Drive is ready.
5092   @retval FALSE Drive is NOT ready.
5093 
5094 **/
5095 BOOLEAN
ScsiDiskIsDriveReady(IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN SenseCounts,OUT BOOLEAN * RetryLater)5096 ScsiDiskIsDriveReady (
5097   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5098   IN  UINTN                 SenseCounts,
5099   OUT BOOLEAN               *RetryLater
5100   )
5101 {
5102   EFI_SCSI_SENSE_DATA *SensePtr;
5103   UINTN               Index;
5104   BOOLEAN             IsReady;
5105 
5106   IsReady     = TRUE;
5107   *RetryLater = FALSE;
5108   SensePtr    = SenseData;
5109 
5110   for (Index = 0; Index < SenseCounts; Index++) {
5111 
5112     switch (SensePtr->Sense_Key) {
5113 
5114     case EFI_SCSI_SK_NOT_READY:
5115       //
5116       // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5117       //
5118       switch (SensePtr->Addnl_Sense_Code) {
5119       case EFI_SCSI_ASC_NOT_READY:
5120         //
5121         // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5122         //
5123         switch (SensePtr->Addnl_Sense_Code_Qualifier) {
5124         case EFI_SCSI_ASCQ_IN_PROGRESS:
5125           //
5126           // Additional Sense Code Qualifier is
5127           // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5128           //
5129           IsReady     = FALSE;
5130           *RetryLater = TRUE;
5131           break;
5132 
5133         default:
5134           IsReady     = FALSE;
5135           *RetryLater = FALSE;
5136           break;
5137         }
5138         break;
5139 
5140       default:
5141         break;
5142       }
5143       break;
5144 
5145     default:
5146       break;
5147     }
5148 
5149     SensePtr++;
5150   }
5151 
5152   return IsReady;
5153 }
5154 
5155 /**
5156   Check sense key to find if it has sense key.
5157 
5158   @param  SenseData   - The pointer of EFI_SCSI_SENSE_DATA
5159   @param  SenseCounts - The number of sense key
5160 
5161   @retval TRUE  It has sense key.
5162   @retval FALSE It has NOT any sense key.
5163 
5164 **/
5165 BOOLEAN
ScsiDiskHaveSenseKey(IN EFI_SCSI_SENSE_DATA * SenseData,IN UINTN SenseCounts)5166 ScsiDiskHaveSenseKey (
5167   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5168   IN  UINTN                 SenseCounts
5169   )
5170 {
5171   EFI_SCSI_SENSE_DATA *SensePtr;
5172   UINTN               Index;
5173   BOOLEAN             HaveSenseKey;
5174 
5175   if (SenseCounts == 0) {
5176     HaveSenseKey = FALSE;
5177   } else {
5178     HaveSenseKey = TRUE;
5179   }
5180 
5181   SensePtr = SenseData;
5182 
5183   for (Index = 0; Index < SenseCounts; Index++) {
5184 
5185     //
5186     // Sense Key is SK_NO_SENSE (0x0)
5187     //
5188     if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
5189         (Index == 0)) {
5190       HaveSenseKey = FALSE;
5191     }
5192 
5193     SensePtr++;
5194   }
5195 
5196   return HaveSenseKey;
5197 }
5198 
5199 /**
5200   Release resource about disk device.
5201 
5202   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
5203 
5204 **/
5205 VOID
ReleaseScsiDiskDeviceResources(IN SCSI_DISK_DEV * ScsiDiskDevice)5206 ReleaseScsiDiskDeviceResources (
5207   IN  SCSI_DISK_DEV   *ScsiDiskDevice
5208   )
5209 {
5210   if (ScsiDiskDevice == NULL) {
5211     return ;
5212   }
5213 
5214   if (ScsiDiskDevice->SenseData != NULL) {
5215     FreePool (ScsiDiskDevice->SenseData);
5216     ScsiDiskDevice->SenseData = NULL;
5217   }
5218 
5219   if (ScsiDiskDevice->ControllerNameTable != NULL) {
5220     FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
5221     ScsiDiskDevice->ControllerNameTable = NULL;
5222   }
5223 
5224   FreePool (ScsiDiskDevice);
5225 
5226   ScsiDiskDevice = NULL;
5227 }
5228 
5229 /**
5230   Determine if Block Io & Block Io2 should be produced.
5231 
5232 
5233   @param  ChildHandle  Child Handle to retrieve Parent information.
5234 
5235   @retval  TRUE    Should produce Block Io & Block Io2.
5236   @retval  FALSE   Should not produce Block Io & Block Io2.
5237 
5238 **/
5239 BOOLEAN
DetermineInstallBlockIo(IN EFI_HANDLE ChildHandle)5240 DetermineInstallBlockIo (
5241   IN  EFI_HANDLE      ChildHandle
5242   )
5243 {
5244   EFI_SCSI_PASS_THRU_PROTOCOL           *ScsiPassThru;
5245   EFI_EXT_SCSI_PASS_THRU_PROTOCOL       *ExtScsiPassThru;
5246 
5247   //
5248   // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5249   // check its attribute, logic or physical.
5250   //
5251   ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
5252   if (ExtScsiPassThru != NULL) {
5253     if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5254       return TRUE;
5255     }
5256   }
5257 
5258   //
5259   // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5260   // check its attribute, logic or physical.
5261   //
5262   ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
5263   if (ScsiPassThru != NULL) {
5264     if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5265       return TRUE;
5266     }
5267   }
5268 
5269   return FALSE;
5270 }
5271 
5272 /**
5273   Search protocol database and check to see if the protocol
5274   specified by ProtocolGuid is present on a ControllerHandle and opened by
5275   ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5276   If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5277   will be opened on it.
5278 
5279 
5280   @param  ProtocolGuid   ProtocolGuid pointer.
5281   @param  ChildHandle    Child Handle to retrieve Parent information.
5282 
5283 **/
5284 VOID *
5285 EFIAPI
GetParentProtocol(IN EFI_GUID * ProtocolGuid,IN EFI_HANDLE ChildHandle)5286 GetParentProtocol (
5287   IN  EFI_GUID                          *ProtocolGuid,
5288   IN  EFI_HANDLE                        ChildHandle
5289   )
5290 {
5291   UINTN                                 Index;
5292   UINTN                                 HandleCount;
5293   VOID                                  *Interface;
5294   EFI_STATUS                            Status;
5295   EFI_HANDLE                            *HandleBuffer;
5296 
5297   //
5298   // Retrieve the list of all handles from the handle database
5299   //
5300   Status = gBS->LocateHandleBuffer (
5301                   ByProtocol,
5302                   ProtocolGuid,
5303                   NULL,
5304                   &HandleCount,
5305                   &HandleBuffer
5306                   );
5307 
5308   if (EFI_ERROR (Status)) {
5309     return NULL;
5310   }
5311 
5312   //
5313   // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5314   //
5315   for (Index = 0; Index < HandleCount; Index++) {
5316     Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
5317     if (!EFI_ERROR (Status)) {
5318       Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
5319       if (!EFI_ERROR (Status)) {
5320         gBS->FreePool (HandleBuffer);
5321         return Interface;
5322       }
5323     }
5324   }
5325 
5326   gBS->FreePool (HandleBuffer);
5327   return NULL;
5328 }
5329 
5330 /**
5331   Determine if EFI Erase Block Protocol should be produced.
5332 
5333   @param   ScsiDiskDevice    The pointer of SCSI_DISK_DEV.
5334   @param   ChildHandle       Handle of device.
5335 
5336   @retval  TRUE    Should produce EFI Erase Block Protocol.
5337   @retval  FALSE   Should not produce EFI Erase Block Protocol.
5338 
5339 **/
5340 BOOLEAN
DetermineInstallEraseBlock(IN SCSI_DISK_DEV * ScsiDiskDevice,IN EFI_HANDLE ChildHandle)5341 DetermineInstallEraseBlock (
5342   IN  SCSI_DISK_DEV          *ScsiDiskDevice,
5343   IN  EFI_HANDLE             ChildHandle
5344   )
5345 {
5346   UINT8                           HostAdapterStatus;
5347   UINT8                           TargetStatus;
5348   EFI_STATUS                      CommandStatus;
5349   EFI_STATUS                      Status;
5350   BOOLEAN                         UfsDevice;
5351   BOOLEAN                         RetVal;
5352   EFI_DEVICE_PATH_PROTOCOL        *DevicePathNode;
5353   UINT8                           SenseDataLength;
5354   UINT32                          DataLength16;
5355   EFI_SCSI_DISK_CAPACITY_DATA16   *CapacityData16;
5356 
5357   UfsDevice      = FALSE;
5358   RetVal         = TRUE;
5359   CapacityData16 = NULL;
5360 
5361   Status = gBS->HandleProtocol (
5362                   ChildHandle,
5363                   &gEfiDevicePathProtocolGuid,
5364                   (VOID **) &DevicePathNode
5365                   );
5366   //
5367   // Device Path protocol must be installed on the device handle.
5368   //
5369   ASSERT_EFI_ERROR (Status);
5370 
5371   while (!IsDevicePathEndType (DevicePathNode)) {
5372     //
5373     // For now, only support Erase Block Protocol on UFS devices.
5374     //
5375     if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
5376         (DevicePathNode->SubType == MSG_UFS_DP)) {
5377       UfsDevice = TRUE;
5378       break;
5379     }
5380 
5381     DevicePathNode = NextDevicePathNode (DevicePathNode);
5382   }
5383   if (!UfsDevice) {
5384     RetVal = FALSE;
5385     goto Done;
5386   }
5387 
5388   //
5389   // Check whether the erase functionality is enabled on the UFS device.
5390   //
5391   CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
5392   if (CapacityData16 == NULL) {
5393     RetVal = FALSE;
5394     goto Done;
5395   }
5396 
5397   SenseDataLength = 0;
5398   DataLength16    = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
5399   ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
5400 
5401   CommandStatus = ScsiReadCapacity16Command (
5402                     ScsiDiskDevice->ScsiIo,
5403                     SCSI_DISK_TIMEOUT,
5404                     NULL,
5405                     &SenseDataLength,
5406                     &HostAdapterStatus,
5407                     &TargetStatus,
5408                     (VOID *) CapacityData16,
5409                     &DataLength16,
5410                     FALSE
5411                     );
5412 
5413   if (CommandStatus == EFI_SUCCESS) {
5414     //
5415     // Universal Flash Storage (UFS) Version 2.0
5416     // Section 11.3.9.2
5417     // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
5418     //
5419     if (((CapacityData16->LowestAlignLogic2 & BIT7) == 0) ||
5420         ((CapacityData16->LowestAlignLogic2 & BIT6) == 0)) {
5421       DEBUG ((
5422         EFI_D_VERBOSE,
5423         "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
5424         CapacityData16->LowestAlignLogic2
5425         ));
5426 
5427       RetVal = FALSE;
5428       goto Done;
5429     }
5430   } else {
5431     DEBUG ((
5432       EFI_D_VERBOSE,
5433       "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
5434       CommandStatus
5435       ));
5436 
5437     RetVal = FALSE;
5438     goto Done;
5439   }
5440 
5441   //
5442   // Check whether the UFS device server implements the UNMAP command.
5443   //
5444   if ((ScsiDiskDevice->UnmapInfo.MaxLbaCnt == 0) ||
5445       (ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt == 0)) {
5446     DEBUG ((
5447       EFI_D_VERBOSE,
5448       "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
5449       ));
5450 
5451     RetVal = FALSE;
5452     goto Done;
5453   }
5454 
5455 Done:
5456   if (CapacityData16 != NULL) {
5457     FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
5458   }
5459 
5460   return RetVal;
5461 }
5462 
5463 /**
5464   Provides inquiry information for the controller type.
5465 
5466   This function is used by the IDE bus driver to get inquiry data.  Data format
5467   of Identify data is defined by the Interface GUID.
5468 
5469   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5470   @param[in, out] InquiryData       Pointer to a buffer for the inquiry data.
5471   @param[in, out] InquiryDataSize   Pointer to the value for the inquiry data size.
5472 
5473   @retval EFI_SUCCESS            The command was accepted without any errors.
5474   @retval EFI_NOT_FOUND          Device does not support this data class
5475   @retval EFI_DEVICE_ERROR       Error reading InquiryData from device
5476   @retval EFI_BUFFER_TOO_SMALL   InquiryDataSize not big enough
5477 
5478 **/
5479 EFI_STATUS
5480 EFIAPI
ScsiDiskInfoInquiry(IN EFI_DISK_INFO_PROTOCOL * This,IN OUT VOID * InquiryData,IN OUT UINT32 * InquiryDataSize)5481 ScsiDiskInfoInquiry (
5482   IN     EFI_DISK_INFO_PROTOCOL   *This,
5483   IN OUT VOID                     *InquiryData,
5484   IN OUT UINT32                   *InquiryDataSize
5485   )
5486 {
5487   EFI_STATUS      Status;
5488   SCSI_DISK_DEV   *ScsiDiskDevice;
5489 
5490   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
5491 
5492   Status = EFI_BUFFER_TOO_SMALL;
5493   if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
5494     Status = EFI_SUCCESS;
5495     CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
5496   }
5497   *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
5498   return Status;
5499 }
5500 
5501 
5502 /**
5503   Provides identify information for the controller type.
5504 
5505   This function is used by the IDE bus driver to get identify data.  Data format
5506   of Identify data is defined by the Interface GUID.
5507 
5508   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL
5509                                     instance.
5510   @param[in, out] IdentifyData      Pointer to a buffer for the identify data.
5511   @param[in, out] IdentifyDataSize  Pointer to the value for the identify data
5512                                     size.
5513 
5514   @retval EFI_SUCCESS            The command was accepted without any errors.
5515   @retval EFI_NOT_FOUND          Device does not support this data class
5516   @retval EFI_DEVICE_ERROR       Error reading IdentifyData from device
5517   @retval EFI_BUFFER_TOO_SMALL   IdentifyDataSize not big enough
5518 
5519 **/
5520 EFI_STATUS
5521 EFIAPI
ScsiDiskInfoIdentify(IN EFI_DISK_INFO_PROTOCOL * This,IN OUT VOID * IdentifyData,IN OUT UINT32 * IdentifyDataSize)5522 ScsiDiskInfoIdentify (
5523   IN     EFI_DISK_INFO_PROTOCOL   *This,
5524   IN OUT VOID                     *IdentifyData,
5525   IN OUT UINT32                   *IdentifyDataSize
5526   )
5527 {
5528   EFI_STATUS      Status;
5529   SCSI_DISK_DEV   *ScsiDiskDevice;
5530 
5531   if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
5532     //
5533     // Physical SCSI bus does not support this data class.
5534     //
5535     return EFI_NOT_FOUND;
5536   }
5537 
5538   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
5539 
5540   Status = EFI_BUFFER_TOO_SMALL;
5541   if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
5542     Status = EFI_SUCCESS;
5543     CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
5544   }
5545   *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
5546   return Status;
5547 }
5548 
5549 /**
5550   Provides sense data information for the controller type.
5551 
5552   This function is used by the IDE bus driver to get sense data.
5553   Data format of Sense data is defined by the Interface GUID.
5554 
5555   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5556   @param[in, out] SenseData         Pointer to the SenseData.
5557   @param[in, out] SenseDataSize     Size of SenseData in bytes.
5558   @param[out]     SenseDataNumber   Pointer to the value for the sense data size.
5559 
5560   @retval EFI_SUCCESS            The command was accepted without any errors.
5561   @retval EFI_NOT_FOUND          Device does not support this data class.
5562   @retval EFI_DEVICE_ERROR       Error reading SenseData from device.
5563   @retval EFI_BUFFER_TOO_SMALL   SenseDataSize not big enough.
5564 
5565 **/
5566 EFI_STATUS
5567 EFIAPI
ScsiDiskInfoSenseData(IN EFI_DISK_INFO_PROTOCOL * This,IN OUT VOID * SenseData,IN OUT UINT32 * SenseDataSize,OUT UINT8 * SenseDataNumber)5568 ScsiDiskInfoSenseData (
5569   IN     EFI_DISK_INFO_PROTOCOL   *This,
5570   IN OUT VOID                     *SenseData,
5571   IN OUT UINT32                   *SenseDataSize,
5572   OUT    UINT8                    *SenseDataNumber
5573   )
5574 {
5575   return EFI_NOT_FOUND;
5576 }
5577 
5578 
5579 /**
5580   This function is used by the IDE bus driver to get controller information.
5581 
5582   @param[in]  This         Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5583   @param[out] IdeChannel   Pointer to the Ide Channel number.  Primary or secondary.
5584   @param[out] IdeDevice    Pointer to the Ide Device number.  Master or slave.
5585 
5586   @retval EFI_SUCCESS       IdeChannel and IdeDevice are valid.
5587   @retval EFI_UNSUPPORTED   This is not an IDE device.
5588 
5589 **/
5590 EFI_STATUS
5591 EFIAPI
ScsiDiskInfoWhichIde(IN EFI_DISK_INFO_PROTOCOL * This,OUT UINT32 * IdeChannel,OUT UINT32 * IdeDevice)5592 ScsiDiskInfoWhichIde (
5593   IN  EFI_DISK_INFO_PROTOCOL   *This,
5594   OUT UINT32                   *IdeChannel,
5595   OUT UINT32                   *IdeDevice
5596   )
5597 {
5598   SCSI_DISK_DEV   *ScsiDiskDevice;
5599 
5600   if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
5601     //
5602     // This is not an IDE physical device.
5603     //
5604     return EFI_UNSUPPORTED;
5605   }
5606 
5607   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
5608   *IdeChannel     = ScsiDiskDevice->Channel;
5609   *IdeDevice      = ScsiDiskDevice->Device;
5610 
5611   return EFI_SUCCESS;
5612 }
5613 
5614 
5615 /**
5616   Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
5617 
5618   This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
5619   implement Identify() interface for DiskInfo protocol. The ATA command is sent
5620   via SCSI Request Packet.
5621 
5622   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
5623 
5624   @retval EFI_SUCCESS     The ATAPI device identify data were retrieved successfully.
5625   @retval others          Some error occurred during the identification that ATAPI device.
5626 
5627 **/
5628 EFI_STATUS
AtapiIdentifyDevice(IN OUT SCSI_DISK_DEV * ScsiDiskDevice)5629 AtapiIdentifyDevice (
5630   IN OUT SCSI_DISK_DEV   *ScsiDiskDevice
5631   )
5632 {
5633   EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
5634   UINT8                           Cdb[6];
5635 
5636   //
5637   // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
5638   //
5639   ZeroMem (&CommandPacket, sizeof (CommandPacket));
5640   ZeroMem (Cdb, sizeof (Cdb));
5641 
5642   Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
5643   CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
5644   CommandPacket.Cdb = Cdb;
5645   CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
5646   CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
5647   CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
5648 
5649   return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
5650 }
5651 
5652 
5653 /**
5654   Initialize the installation of DiskInfo protocol.
5655 
5656   This function prepares for the installation of DiskInfo protocol on the child handle.
5657   By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
5658   detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
5659   to be IDE/AHCI interface GUID.
5660 
5661   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
5662   @param  ChildHandle     Child handle to install DiskInfo protocol.
5663 
5664 **/
5665 VOID
InitializeInstallDiskInfo(IN SCSI_DISK_DEV * ScsiDiskDevice,IN EFI_HANDLE ChildHandle)5666 InitializeInstallDiskInfo (
5667   IN  SCSI_DISK_DEV   *ScsiDiskDevice,
5668   IN  EFI_HANDLE      ChildHandle
5669   )
5670 {
5671   EFI_STATUS                Status;
5672   EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;
5673   EFI_DEVICE_PATH_PROTOCOL  *ChildDevicePathNode;
5674   ATAPI_DEVICE_PATH         *AtapiDevicePath;
5675   SATA_DEVICE_PATH          *SataDevicePath;
5676   UINTN                     IdentifyRetry;
5677 
5678   Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
5679   //
5680   // Device Path protocol must be installed on the device handle.
5681   //
5682   ASSERT_EFI_ERROR (Status);
5683   //
5684   // Copy the DiskInfo protocol template.
5685   //
5686   CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
5687 
5688   while (!IsDevicePathEnd (DevicePathNode)) {
5689     ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
5690     if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
5691         (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
5692         (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
5693        ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
5694         (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
5695 
5696       IdentifyRetry = 3;
5697       do {
5698         //
5699         // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
5700         // with IDE/AHCI interface GUID.
5701         //
5702         Status = AtapiIdentifyDevice (ScsiDiskDevice);
5703         if (!EFI_ERROR (Status)) {
5704           if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
5705             //
5706             // We find the valid ATAPI device path
5707             //
5708             AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
5709             ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
5710             ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
5711             //
5712             // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5713             //
5714             CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
5715           } else {
5716             //
5717             // We find the valid SATA device path
5718             //
5719             SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
5720             ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
5721             ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
5722             //
5723             // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5724             //
5725             CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
5726           }
5727           return;
5728         }
5729       } while (--IdentifyRetry > 0);
5730     } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
5731        (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) {
5732       CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
5733       break;
5734     }
5735     DevicePathNode = ChildDevicePathNode;
5736   }
5737 
5738   return;
5739 }
5740