TianoCore EDK2 master
Loading...
Searching...
No Matches
ScsiDisk.c
Go to the documentation of this file.
1
10#include "ScsiDisk.h"
11
12EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
16 0xa,
17 NULL,
18 NULL
19};
20
21EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
27};
28
41VOID *
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
60VOID
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
80 IN OUT CHAR8 *String
81 )
82{
83 UINTN Length;
84
85 Length = AsciiStrLen (String);
86 if (Length == 0) {
87 return 0;
88 }
89
90 while ((Length > 0) && (String[Length-1] == ' ')) {
91 Length--;
92 }
93
94 String[Length] = '\0';
95 return Length;
96}
97
111EFIAPI
113 IN EFI_HANDLE ImageHandle,
114 IN EFI_SYSTEM_TABLE *SystemTable
115 )
116{
117 EFI_STATUS Status;
118
119 //
120 // Install driver model protocol(s).
121 //
123 ImageHandle,
124 SystemTable,
125 &gScsiDiskDriverBinding,
126 ImageHandle,
127 &gScsiDiskComponentName,
128 &gScsiDiskComponentName2
129 );
130 ASSERT_EFI_ERROR (Status);
131
132 return Status;
133}
134
155EFIAPI
158 IN EFI_HANDLE Controller,
159 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
160 )
161{
162 EFI_STATUS Status;
163 EFI_SCSI_IO_PROTOCOL *ScsiIo;
164 UINT8 DeviceType;
165
166 Status = gBS->OpenProtocol (
167 Controller,
168 &gEfiScsiIoProtocolGuid,
169 (VOID **)&ScsiIo,
170 This->DriverBindingHandle,
171 Controller,
172 EFI_OPEN_PROTOCOL_BY_DRIVER
173 );
174 if (EFI_ERROR (Status)) {
175 return Status;
176 }
177
178 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
179 if (!EFI_ERROR (Status)) {
180 if ((DeviceType == EFI_SCSI_TYPE_DISK) ||
181 (DeviceType == EFI_SCSI_TYPE_CDROM) ||
182 (DeviceType == EFI_SCSI_TYPE_WLUN))
183 {
184 Status = EFI_SUCCESS;
185 } else {
186 Status = EFI_UNSUPPORTED;
187 }
188 }
189
190 gBS->CloseProtocol (
191 Controller,
192 &gEfiScsiIoProtocolGuid,
193 This->DriverBindingHandle,
194 Controller
195 );
196 return Status;
197}
198
219EFIAPI
222 IN EFI_HANDLE Controller,
223 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
224 )
225{
226 EFI_STATUS Status;
227 EFI_SCSI_IO_PROTOCOL *ScsiIo;
228 SCSI_DISK_DEV *ScsiDiskDevice;
229 BOOLEAN Temp;
230 UINT8 Index;
231 UINT8 MaxRetry;
232 BOOLEAN NeedRetry;
233 BOOLEAN MustReadCapacity;
234 CHAR8 VendorStr[VENDOR_IDENTIFICATION_LENGTH + 1];
235 CHAR8 ProductStr[PRODUCT_IDENTIFICATION_LENGTH + 1];
236 CHAR16 DeviceStr[VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2];
237
238 MustReadCapacity = TRUE;
239
240 ScsiDiskDevice = (SCSI_DISK_DEV *)AllocateZeroPool (sizeof (SCSI_DISK_DEV));
241 if (ScsiDiskDevice == NULL) {
242 return EFI_OUT_OF_RESOURCES;
243 }
244
245 Status = gBS->OpenProtocol (
246 Controller,
247 &gEfiScsiIoProtocolGuid,
248 (VOID **)&ScsiIo,
249 This->DriverBindingHandle,
250 Controller,
251 EFI_OPEN_PROTOCOL_BY_DRIVER
252 );
253 if (EFI_ERROR (Status)) {
254 FreePool (ScsiDiskDevice);
255 return Status;
256 }
257
258 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;
259 ScsiDiskDevice->ScsiIo = ScsiIo;
260 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
261 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;
262 ScsiDiskDevice->BlkIo.Media->IoAlign = ScsiIo->IoAlign;
263 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;
264 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;
265 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;
266 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;
267 ScsiDiskDevice->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia;
268 ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx;
269 ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx;
270 ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;
271 ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;
272 ScsiDiskDevice->StorageSecurity.ReceiveData = ScsiDiskReceiveData;
273 ScsiDiskDevice->StorageSecurity.SendData = ScsiDiskSendData;
274 ScsiDiskDevice->EraseBlock.Revision = EFI_ERASE_BLOCK_PROTOCOL_REVISION;
275 ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
276 ScsiDiskDevice->EraseBlock.EraseBlocks = ScsiDiskEraseBlocks;
277 ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt = 1;
278 ScsiDiskDevice->BlockLimitsVpdSupported = FALSE;
279 ScsiDiskDevice->Handle = Controller;
280 InitializeListHead (&ScsiDiskDevice->AsyncTaskQueue);
281
282 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
283 switch (ScsiDiskDevice->DeviceType) {
285 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
286 MustReadCapacity = TRUE;
287 break;
288
290 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
291 ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;
292 MustReadCapacity = FALSE;
293 break;
294
296 MustReadCapacity = FALSE;
297 break;
298 }
299
300 //
301 // The Sense Data Array's initial size is 6
302 //
303 ScsiDiskDevice->SenseDataNumber = 6;
304 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *)AllocateZeroPool (
305 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
306 );
307 if (ScsiDiskDevice->SenseData == NULL) {
308 gBS->CloseProtocol (
309 Controller,
310 &gEfiScsiIoProtocolGuid,
311 This->DriverBindingHandle,
312 Controller
313 );
314 FreePool (ScsiDiskDevice);
315 return EFI_OUT_OF_RESOURCES;
316 }
317
318 //
319 // Retrieve device information
320 //
321 MaxRetry = 2;
322 for (Index = 0; Index < MaxRetry; Index++) {
323 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
324 if (!EFI_ERROR (Status)) {
325 break;
326 }
327
328 if (!NeedRetry) {
329 FreePool (ScsiDiskDevice->SenseData);
330 gBS->CloseProtocol (
331 Controller,
332 &gEfiScsiIoProtocolGuid,
333 This->DriverBindingHandle,
334 Controller
335 );
336 FreePool (ScsiDiskDevice);
337 return EFI_DEVICE_ERROR;
338 }
339 }
340
341 //
342 // The second parameter "TRUE" means must
343 // retrieve media capacity
344 //
345 Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
346 if (!EFI_ERROR (Status)) {
347 //
348 // Determine if Block IO & Block IO2 should be produced on this controller
349 // handle
350 //
351 if (DetermineInstallBlockIo (Controller)) {
352 InitializeInstallDiskInfo (ScsiDiskDevice, Controller);
353 Status = gBS->InstallMultipleProtocolInterfaces (
354 &Controller,
355 &gEfiBlockIoProtocolGuid,
356 &ScsiDiskDevice->BlkIo,
357 &gEfiBlockIo2ProtocolGuid,
358 &ScsiDiskDevice->BlkIo2,
359 &gEfiDiskInfoProtocolGuid,
360 &ScsiDiskDevice->DiskInfo,
361 NULL
362 );
363 if (!EFI_ERROR (Status)) {
364 if (DetermineInstallEraseBlock (ScsiDiskDevice, Controller)) {
365 Status = gBS->InstallProtocolInterface (
366 &Controller,
367 &gEfiEraseBlockProtocolGuid,
369 &ScsiDiskDevice->EraseBlock
370 );
371 if (EFI_ERROR (Status)) {
372 DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status));
373 }
374 }
375
376 if (DetermineInstallStorageSecurity (ScsiDiskDevice, Controller)) {
377 Status = gBS->InstallProtocolInterface (
378 &Controller,
379 &gEfiStorageSecurityCommandProtocolGuid,
381 &ScsiDiskDevice->StorageSecurity
382 );
383 if (EFI_ERROR (Status)) {
384 DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status));
385 }
386 }
387
388 CopyMem (
389 VendorStr,
390 &ScsiDiskDevice->InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET],
391 VENDOR_IDENTIFICATION_LENGTH
392 );
393 VendorStr[VENDOR_IDENTIFICATION_LENGTH] = 0;
394 RemoveTrailingSpaces (VendorStr);
395
396 CopyMem (
397 ProductStr,
398 &ScsiDiskDevice->InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET],
399 PRODUCT_IDENTIFICATION_LENGTH
400 );
401 ProductStr[PRODUCT_IDENTIFICATION_LENGTH] = 0;
402 RemoveTrailingSpaces (ProductStr);
403
404 UnicodeSPrint (DeviceStr, sizeof (DeviceStr), L"%a %a", VendorStr, ProductStr);
405
406 ScsiDiskDevice->ControllerNameTable = NULL;
408 "eng",
409 gScsiDiskComponentName.SupportedLanguages,
410 &ScsiDiskDevice->ControllerNameTable,
411 DeviceStr,
412 TRUE
413 );
415 "en",
416 gScsiDiskComponentName2.SupportedLanguages,
417 &ScsiDiskDevice->ControllerNameTable,
418 DeviceStr,
419 FALSE
420 );
421 return EFI_SUCCESS;
422 }
423 }
424 }
425
426 gBS->FreePool (ScsiDiskDevice->SenseData);
427 gBS->FreePool (ScsiDiskDevice);
428 gBS->CloseProtocol (
429 Controller,
430 &gEfiScsiIoProtocolGuid,
431 This->DriverBindingHandle,
432 Controller
433 );
434 return Status;
435}
436
457EFIAPI
460 IN EFI_HANDLE Controller,
461 IN UINTN NumberOfChildren,
462 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
463 )
464{
466 EFI_ERASE_BLOCK_PROTOCOL *EraseBlock;
467 SCSI_DISK_DEV *ScsiDiskDevice;
468 EFI_STATUS Status;
469
470 Status = gBS->OpenProtocol (
471 Controller,
472 &gEfiBlockIoProtocolGuid,
473 (VOID **)&BlkIo,
474 This->DriverBindingHandle,
475 Controller,
476 EFI_OPEN_PROTOCOL_GET_PROTOCOL
477 );
478 if (EFI_ERROR (Status)) {
479 return Status;
480 }
481
482 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);
483
484 //
485 // Wait for the BlockIo2 requests queue to become empty
486 //
487 while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue)) {
488 }
489
490 //
491 // If Erase Block Protocol is installed, then uninstall this protocol.
492 //
493 Status = gBS->OpenProtocol (
494 Controller,
495 &gEfiEraseBlockProtocolGuid,
496 (VOID **)&EraseBlock,
497 This->DriverBindingHandle,
498 Controller,
499 EFI_OPEN_PROTOCOL_GET_PROTOCOL
500 );
501
502 if (!EFI_ERROR (Status)) {
503 Status = gBS->UninstallProtocolInterface (
504 Controller,
505 &gEfiEraseBlockProtocolGuid,
506 &ScsiDiskDevice->EraseBlock
507 );
508 if (EFI_ERROR (Status)) {
509 return Status;
510 }
511 }
512
513 Status = gBS->UninstallMultipleProtocolInterfaces (
514 Controller,
515 &gEfiBlockIoProtocolGuid,
516 &ScsiDiskDevice->BlkIo,
517 &gEfiBlockIo2ProtocolGuid,
518 &ScsiDiskDevice->BlkIo2,
519 &gEfiDiskInfoProtocolGuid,
520 &ScsiDiskDevice->DiskInfo,
521 NULL
522 );
523 if (!EFI_ERROR (Status)) {
524 gBS->CloseProtocol (
525 Controller,
526 &gEfiScsiIoProtocolGuid,
527 This->DriverBindingHandle,
528 Controller
529 );
530
531 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
532
533 return EFI_SUCCESS;
534 }
535
536 //
537 // errors met
538 //
539 return Status;
540}
541
556EFIAPI
559 IN BOOLEAN ExtendedVerification
560 )
561{
562 EFI_TPL OldTpl;
563 SCSI_DISK_DEV *ScsiDiskDevice;
564 EFI_STATUS Status;
565
566 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
567
568 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
569
570 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
571
572 if (EFI_ERROR (Status)) {
573 if (Status == EFI_UNSUPPORTED) {
574 Status = EFI_SUCCESS;
575 } else {
576 Status = EFI_DEVICE_ERROR;
577 goto Done;
578 }
579 }
580
581 if (!ExtendedVerification) {
582 goto Done;
583 }
584
585 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
586
587 if (EFI_ERROR (Status)) {
588 Status = EFI_DEVICE_ERROR;
589 goto Done;
590 }
591
592Done:
593 gBS->RestoreTPL (OldTpl);
594 return Status;
595}
596
615EFIAPI
618 IN UINT32 MediaId,
619 IN EFI_LBA Lba,
620 IN UINTN BufferSize,
621 OUT VOID *Buffer
622 )
623{
624 SCSI_DISK_DEV *ScsiDiskDevice;
625 EFI_BLOCK_IO_MEDIA *Media;
626 EFI_STATUS Status;
627 UINTN BlockSize;
628 UINTN NumberOfBlocks;
629 BOOLEAN MediaChange;
630 EFI_TPL OldTpl;
631
632 MediaChange = FALSE;
633 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
634 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
635 Media = ScsiDiskDevice->BlkIo.Media;
636
637 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
638 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
639 if (EFI_ERROR (Status)) {
640 Status = EFI_DEVICE_ERROR;
641 goto Done;
642 }
643
644 if (MediaChange) {
645 gBS->ReinstallProtocolInterface (
646 ScsiDiskDevice->Handle,
647 &gEfiBlockIoProtocolGuid,
648 &ScsiDiskDevice->BlkIo,
649 &ScsiDiskDevice->BlkIo
650 );
651 gBS->ReinstallProtocolInterface (
652 ScsiDiskDevice->Handle,
653 &gEfiBlockIo2ProtocolGuid,
654 &ScsiDiskDevice->BlkIo2,
655 &ScsiDiskDevice->BlkIo2
656 );
657 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
658 gBS->ReinstallProtocolInterface (
659 ScsiDiskDevice->Handle,
660 &gEfiEraseBlockProtocolGuid,
661 &ScsiDiskDevice->EraseBlock,
662 &ScsiDiskDevice->EraseBlock
663 );
664 }
665
666 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
667 gBS->ReinstallProtocolInterface (
668 ScsiDiskDevice->Handle,
669 &gEfiStorageSecurityCommandProtocolGuid,
670 &ScsiDiskDevice->StorageSecurity,
671 &ScsiDiskDevice->StorageSecurity
672 );
673 }
674
675 if (Media->MediaPresent) {
676 Status = EFI_MEDIA_CHANGED;
677 } else {
678 Status = EFI_NO_MEDIA;
679 }
680
681 goto Done;
682 }
683 }
684
685 //
686 // Get the intrinsic block size
687 //
688 BlockSize = Media->BlockSize;
689
690 if (BlockSize == 0) {
691 Status = EFI_DEVICE_ERROR;
692 goto Done;
693 }
694
695 NumberOfBlocks = BufferSize / BlockSize;
696
697 if (!(Media->MediaPresent)) {
698 Status = EFI_NO_MEDIA;
699 goto Done;
700 }
701
702 if (MediaId != Media->MediaId) {
703 Status = EFI_MEDIA_CHANGED;
704 goto Done;
705 }
706
707 if (Buffer == NULL) {
708 Status = EFI_INVALID_PARAMETER;
709 goto Done;
710 }
711
712 if (BufferSize == 0) {
713 Status = EFI_SUCCESS;
714 goto Done;
715 }
716
717 if (BufferSize % BlockSize != 0) {
718 Status = EFI_BAD_BUFFER_SIZE;
719 goto Done;
720 }
721
722 if (Lba > Media->LastBlock) {
723 Status = EFI_INVALID_PARAMETER;
724 goto Done;
725 }
726
727 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
728 Status = EFI_INVALID_PARAMETER;
729 goto Done;
730 }
731
732 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
733 Status = EFI_INVALID_PARAMETER;
734 goto Done;
735 }
736
737 //
738 // If all the parameters are valid, then perform read sectors command
739 // to transfer data from device to host.
740 //
741 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
742
743Done:
744 gBS->RestoreTPL (OldTpl);
745 return Status;
746}
747
767EFIAPI
770 IN UINT32 MediaId,
771 IN EFI_LBA Lba,
772 IN UINTN BufferSize,
773 IN VOID *Buffer
774 )
775{
776 SCSI_DISK_DEV *ScsiDiskDevice;
777 EFI_BLOCK_IO_MEDIA *Media;
778 EFI_STATUS Status;
779 UINTN BlockSize;
780 UINTN NumberOfBlocks;
781 BOOLEAN MediaChange;
782 EFI_TPL OldTpl;
783
784 MediaChange = FALSE;
785 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
786 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
787 Media = ScsiDiskDevice->BlkIo.Media;
788
789 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
790 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
791 if (EFI_ERROR (Status)) {
792 Status = EFI_DEVICE_ERROR;
793 goto Done;
794 }
795
796 if (MediaChange) {
797 gBS->ReinstallProtocolInterface (
798 ScsiDiskDevice->Handle,
799 &gEfiBlockIoProtocolGuid,
800 &ScsiDiskDevice->BlkIo,
801 &ScsiDiskDevice->BlkIo
802 );
803 gBS->ReinstallProtocolInterface (
804 ScsiDiskDevice->Handle,
805 &gEfiBlockIo2ProtocolGuid,
806 &ScsiDiskDevice->BlkIo2,
807 &ScsiDiskDevice->BlkIo2
808 );
809 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
810 gBS->ReinstallProtocolInterface (
811 ScsiDiskDevice->Handle,
812 &gEfiEraseBlockProtocolGuid,
813 &ScsiDiskDevice->EraseBlock,
814 &ScsiDiskDevice->EraseBlock
815 );
816 }
817
818 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
819 gBS->ReinstallProtocolInterface (
820 ScsiDiskDevice->Handle,
821 &gEfiStorageSecurityCommandProtocolGuid,
822 &ScsiDiskDevice->StorageSecurity,
823 &ScsiDiskDevice->StorageSecurity
824 );
825 }
826
827 if (Media->MediaPresent) {
828 Status = EFI_MEDIA_CHANGED;
829 } else {
830 Status = EFI_NO_MEDIA;
831 }
832
833 goto Done;
834 }
835 }
836
837 //
838 // Get the intrinsic block size
839 //
840 BlockSize = Media->BlockSize;
841
842 if (BlockSize == 0) {
843 Status = EFI_DEVICE_ERROR;
844 goto Done;
845 }
846
847 NumberOfBlocks = BufferSize / BlockSize;
848
849 if (!(Media->MediaPresent)) {
850 Status = EFI_NO_MEDIA;
851 goto Done;
852 }
853
854 if (MediaId != Media->MediaId) {
855 Status = EFI_MEDIA_CHANGED;
856 goto Done;
857 }
858
859 if (Media->ReadOnly) {
860 Status = EFI_WRITE_PROTECTED;
861 goto Done;
862 }
863
864 if (BufferSize == 0) {
865 Status = EFI_SUCCESS;
866 goto Done;
867 }
868
869 if (Buffer == NULL) {
870 Status = EFI_INVALID_PARAMETER;
871 goto Done;
872 }
873
874 if (BufferSize % BlockSize != 0) {
875 Status = EFI_BAD_BUFFER_SIZE;
876 goto Done;
877 }
878
879 if (Lba > Media->LastBlock) {
880 Status = EFI_INVALID_PARAMETER;
881 goto Done;
882 }
883
884 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
885 Status = EFI_INVALID_PARAMETER;
886 goto Done;
887 }
888
889 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
890 Status = EFI_INVALID_PARAMETER;
891 goto Done;
892 }
893
894 //
895 // if all the parameters are valid, then perform read sectors command
896 // to transfer data from device to host.
897 //
898 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
899
900Done:
901 gBS->RestoreTPL (OldTpl);
902 return Status;
903}
904
916EFIAPI
919 )
920{
921 //
922 // return directly
923 //
924 return EFI_SUCCESS;
925}
926
940EFIAPI
943 IN BOOLEAN ExtendedVerification
944 )
945{
946 EFI_TPL OldTpl;
947 SCSI_DISK_DEV *ScsiDiskDevice;
948 EFI_STATUS Status;
949
950 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
951
952 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
953
954 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
955
956 if (EFI_ERROR (Status)) {
957 if (Status == EFI_UNSUPPORTED) {
958 Status = EFI_SUCCESS;
959 } else {
960 Status = EFI_DEVICE_ERROR;
961 goto Done;
962 }
963 }
964
965 if (!ExtendedVerification) {
966 goto Done;
967 }
968
969 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
970
971 if (EFI_ERROR (Status)) {
972 Status = EFI_DEVICE_ERROR;
973 goto Done;
974 }
975
976Done:
977 gBS->RestoreTPL (OldTpl);
978 return Status;
979}
980
1008EFIAPI
1011 IN UINT32 MediaId,
1012 IN EFI_LBA Lba,
1013 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
1014 IN UINTN BufferSize,
1015 OUT VOID *Buffer
1016 )
1017{
1018 SCSI_DISK_DEV *ScsiDiskDevice;
1019 EFI_BLOCK_IO_MEDIA *Media;
1020 EFI_STATUS Status;
1021 UINTN BlockSize;
1022 UINTN NumberOfBlocks;
1023 BOOLEAN MediaChange;
1024 EFI_TPL OldTpl;
1025
1026 MediaChange = FALSE;
1027 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1028 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1029 Media = ScsiDiskDevice->BlkIo.Media;
1030
1031 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
1032 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1033 if (EFI_ERROR (Status)) {
1034 Status = EFI_DEVICE_ERROR;
1035 goto Done;
1036 }
1037
1038 if (MediaChange) {
1039 gBS->ReinstallProtocolInterface (
1040 ScsiDiskDevice->Handle,
1041 &gEfiBlockIoProtocolGuid,
1042 &ScsiDiskDevice->BlkIo,
1043 &ScsiDiskDevice->BlkIo
1044 );
1045 gBS->ReinstallProtocolInterface (
1046 ScsiDiskDevice->Handle,
1047 &gEfiBlockIo2ProtocolGuid,
1048 &ScsiDiskDevice->BlkIo2,
1049 &ScsiDiskDevice->BlkIo2
1050 );
1051 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1052 gBS->ReinstallProtocolInterface (
1053 ScsiDiskDevice->Handle,
1054 &gEfiEraseBlockProtocolGuid,
1055 &ScsiDiskDevice->EraseBlock,
1056 &ScsiDiskDevice->EraseBlock
1057 );
1058 }
1059
1060 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1061 gBS->ReinstallProtocolInterface (
1062 ScsiDiskDevice->Handle,
1063 &gEfiStorageSecurityCommandProtocolGuid,
1064 &ScsiDiskDevice->StorageSecurity,
1065 &ScsiDiskDevice->StorageSecurity
1066 );
1067 }
1068
1069 if (Media->MediaPresent) {
1070 Status = EFI_MEDIA_CHANGED;
1071 } else {
1072 Status = EFI_NO_MEDIA;
1073 }
1074
1075 goto Done;
1076 }
1077 }
1078
1079 //
1080 // Get the intrinsic block size
1081 //
1082 BlockSize = Media->BlockSize;
1083
1084 if (BlockSize == 0) {
1085 Status = EFI_DEVICE_ERROR;
1086 goto Done;
1087 }
1088
1089 NumberOfBlocks = BufferSize / BlockSize;
1090
1091 if (!(Media->MediaPresent)) {
1092 Status = EFI_NO_MEDIA;
1093 goto Done;
1094 }
1095
1096 if (MediaId != Media->MediaId) {
1097 Status = EFI_MEDIA_CHANGED;
1098 goto Done;
1099 }
1100
1101 if (Buffer == NULL) {
1102 Status = EFI_INVALID_PARAMETER;
1103 goto Done;
1104 }
1105
1106 if (BufferSize == 0) {
1107 if ((Token != NULL) && (Token->Event != NULL)) {
1108 Token->TransactionStatus = EFI_SUCCESS;
1109 gBS->SignalEvent (Token->Event);
1110 }
1111
1112 Status = EFI_SUCCESS;
1113 goto Done;
1114 }
1115
1116 if (BufferSize % BlockSize != 0) {
1117 Status = EFI_BAD_BUFFER_SIZE;
1118 goto Done;
1119 }
1120
1121 if (Lba > Media->LastBlock) {
1122 Status = EFI_INVALID_PARAMETER;
1123 goto Done;
1124 }
1125
1126 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1127 Status = EFI_INVALID_PARAMETER;
1128 goto Done;
1129 }
1130
1131 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
1132 Status = EFI_INVALID_PARAMETER;
1133 goto Done;
1134 }
1135
1136 //
1137 // If all the parameters are valid, then perform read sectors command
1138 // to transfer data from device to host.
1139 //
1140 if ((Token != NULL) && (Token->Event != NULL)) {
1141 Token->TransactionStatus = EFI_SUCCESS;
1142 Status = ScsiDiskAsyncReadSectors (
1143 ScsiDiskDevice,
1144 Buffer,
1145 Lba,
1146 NumberOfBlocks,
1147 Token
1148 );
1149 } else {
1150 Status = ScsiDiskReadSectors (
1151 ScsiDiskDevice,
1152 Buffer,
1153 Lba,
1154 NumberOfBlocks
1155 );
1156 }
1157
1158Done:
1159 gBS->RestoreTPL (OldTpl);
1160 return Status;
1161}
1162
1187EFIAPI
1190 IN UINT32 MediaId,
1191 IN EFI_LBA Lba,
1192 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
1193 IN UINTN BufferSize,
1194 IN VOID *Buffer
1195 )
1196{
1197 SCSI_DISK_DEV *ScsiDiskDevice;
1198 EFI_BLOCK_IO_MEDIA *Media;
1199 EFI_STATUS Status;
1200 UINTN BlockSize;
1201 UINTN NumberOfBlocks;
1202 BOOLEAN MediaChange;
1203 EFI_TPL OldTpl;
1204
1205 MediaChange = FALSE;
1206 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1207 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1208 Media = ScsiDiskDevice->BlkIo.Media;
1209
1210 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
1211 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1212 if (EFI_ERROR (Status)) {
1213 Status = EFI_DEVICE_ERROR;
1214 goto Done;
1215 }
1216
1217 if (MediaChange) {
1218 gBS->ReinstallProtocolInterface (
1219 ScsiDiskDevice->Handle,
1220 &gEfiBlockIoProtocolGuid,
1221 &ScsiDiskDevice->BlkIo,
1222 &ScsiDiskDevice->BlkIo
1223 );
1224 gBS->ReinstallProtocolInterface (
1225 ScsiDiskDevice->Handle,
1226 &gEfiBlockIo2ProtocolGuid,
1227 &ScsiDiskDevice->BlkIo2,
1228 &ScsiDiskDevice->BlkIo2
1229 );
1230 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1231 gBS->ReinstallProtocolInterface (
1232 ScsiDiskDevice->Handle,
1233 &gEfiEraseBlockProtocolGuid,
1234 &ScsiDiskDevice->EraseBlock,
1235 &ScsiDiskDevice->EraseBlock
1236 );
1237 }
1238
1239 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1240 gBS->ReinstallProtocolInterface (
1241 ScsiDiskDevice->Handle,
1242 &gEfiStorageSecurityCommandProtocolGuid,
1243 &ScsiDiskDevice->StorageSecurity,
1244 &ScsiDiskDevice->StorageSecurity
1245 );
1246 }
1247
1248 if (Media->MediaPresent) {
1249 Status = EFI_MEDIA_CHANGED;
1250 } else {
1251 Status = EFI_NO_MEDIA;
1252 }
1253
1254 goto Done;
1255 }
1256 }
1257
1258 //
1259 // Get the intrinsic block size
1260 //
1261 BlockSize = Media->BlockSize;
1262
1263 if (BlockSize == 0) {
1264 Status = EFI_DEVICE_ERROR;
1265 goto Done;
1266 }
1267
1268 NumberOfBlocks = BufferSize / BlockSize;
1269
1270 if (!(Media->MediaPresent)) {
1271 Status = EFI_NO_MEDIA;
1272 goto Done;
1273 }
1274
1275 if (MediaId != Media->MediaId) {
1276 Status = EFI_MEDIA_CHANGED;
1277 goto Done;
1278 }
1279
1280 if (Media->ReadOnly) {
1281 Status = EFI_WRITE_PROTECTED;
1282 goto Done;
1283 }
1284
1285 if (BufferSize == 0) {
1286 if ((Token != NULL) && (Token->Event != NULL)) {
1287 Token->TransactionStatus = EFI_SUCCESS;
1288 gBS->SignalEvent (Token->Event);
1289 }
1290
1291 Status = EFI_SUCCESS;
1292 goto Done;
1293 }
1294
1295 if (Buffer == NULL) {
1296 Status = EFI_INVALID_PARAMETER;
1297 goto Done;
1298 }
1299
1300 if (BufferSize % BlockSize != 0) {
1301 Status = EFI_BAD_BUFFER_SIZE;
1302 goto Done;
1303 }
1304
1305 if (Lba > Media->LastBlock) {
1306 Status = EFI_INVALID_PARAMETER;
1307 goto Done;
1308 }
1309
1310 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1311 Status = EFI_INVALID_PARAMETER;
1312 goto Done;
1313 }
1314
1315 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
1316 Status = EFI_INVALID_PARAMETER;
1317 goto Done;
1318 }
1319
1320 //
1321 // if all the parameters are valid, then perform write sectors command
1322 // to transfer data from device to host.
1323 //
1324 if ((Token != NULL) && (Token->Event != NULL)) {
1325 Token->TransactionStatus = EFI_SUCCESS;
1326 Status = ScsiDiskAsyncWriteSectors (
1327 ScsiDiskDevice,
1328 Buffer,
1329 Lba,
1330 NumberOfBlocks,
1331 Token
1332 );
1333 } else {
1334 Status = ScsiDiskWriteSectors (
1335 ScsiDiskDevice,
1336 Buffer,
1337 Lba,
1338 NumberOfBlocks
1339 );
1340 }
1341
1342Done:
1343 gBS->RestoreTPL (OldTpl);
1344 return Status;
1345}
1346
1362EFIAPI
1366 )
1367{
1368 SCSI_DISK_DEV *ScsiDiskDevice;
1369 EFI_BLOCK_IO_MEDIA *Media;
1370 EFI_STATUS Status;
1371 BOOLEAN MediaChange;
1372 EFI_TPL OldTpl;
1373
1374 MediaChange = FALSE;
1375 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1376 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1377 Media = ScsiDiskDevice->BlkIo.Media;
1378
1379 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
1380 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1381 if (EFI_ERROR (Status)) {
1382 Status = EFI_DEVICE_ERROR;
1383 goto Done;
1384 }
1385
1386 if (MediaChange) {
1387 gBS->ReinstallProtocolInterface (
1388 ScsiDiskDevice->Handle,
1389 &gEfiBlockIoProtocolGuid,
1390 &ScsiDiskDevice->BlkIo,
1391 &ScsiDiskDevice->BlkIo
1392 );
1393 gBS->ReinstallProtocolInterface (
1394 ScsiDiskDevice->Handle,
1395 &gEfiBlockIo2ProtocolGuid,
1396 &ScsiDiskDevice->BlkIo2,
1397 &ScsiDiskDevice->BlkIo2
1398 );
1399 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1400 gBS->ReinstallProtocolInterface (
1401 ScsiDiskDevice->Handle,
1402 &gEfiEraseBlockProtocolGuid,
1403 &ScsiDiskDevice->EraseBlock,
1404 &ScsiDiskDevice->EraseBlock
1405 );
1406 }
1407
1408 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1409 gBS->ReinstallProtocolInterface (
1410 ScsiDiskDevice->Handle,
1411 &gEfiStorageSecurityCommandProtocolGuid,
1412 &ScsiDiskDevice->StorageSecurity,
1413 &ScsiDiskDevice->StorageSecurity
1414 );
1415 }
1416
1417 if (Media->MediaPresent) {
1418 Status = EFI_MEDIA_CHANGED;
1419 } else {
1420 Status = EFI_NO_MEDIA;
1421 }
1422
1423 goto Done;
1424 }
1425 }
1426
1427 if (!(Media->MediaPresent)) {
1428 Status = EFI_NO_MEDIA;
1429 goto Done;
1430 }
1431
1432 if (Media->ReadOnly) {
1433 Status = EFI_WRITE_PROTECTED;
1434 goto Done;
1435 }
1436
1437 //
1438 // Wait for the BlockIo2 requests queue to become empty
1439 //
1440 while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue)) {
1441 }
1442
1443 Status = EFI_SUCCESS;
1444
1445 //
1446 // Signal caller event
1447 //
1448 if ((Token != NULL) && (Token->Event != NULL)) {
1449 Token->TransactionStatus = EFI_SUCCESS;
1450 gBS->SignalEvent (Token->Event);
1451 }
1452
1453Done:
1454 gBS->RestoreTPL (OldTpl);
1455 return Status;
1456}
1457
1466VOID
1467EFIAPI
1469 IN EFI_EVENT Event,
1470 IN VOID *Context
1471 )
1472{
1473 SCSI_ERASEBLK_REQUEST *EraseBlkReq;
1474 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
1475 EFI_ERASE_BLOCK_TOKEN *Token;
1476 EFI_STATUS Status;
1477
1478 gBS->CloseEvent (Event);
1479
1480 EraseBlkReq = (SCSI_ERASEBLK_REQUEST *)Context;
1481 CommandPacket = &EraseBlkReq->CommandPacket;
1482 Token = EraseBlkReq->Token;
1483 Token->TransactionStatus = EFI_SUCCESS;
1484
1485 Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
1486 if (EFI_ERROR (Status)) {
1487 DEBUG ((
1488 DEBUG_ERROR,
1489 "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1490 CommandPacket->HostAdapterStatus
1491 ));
1492
1493 Token->TransactionStatus = Status;
1494 goto Done;
1495 }
1496
1497 Status = CheckTargetStatus (CommandPacket->TargetStatus);
1498 if (EFI_ERROR (Status)) {
1499 DEBUG ((
1500 DEBUG_ERROR,
1501 "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1502 CommandPacket->HostAdapterStatus
1503 ));
1504
1505 Token->TransactionStatus = Status;
1506 goto Done;
1507 }
1508
1509Done:
1510 RemoveEntryList (&EraseBlkReq->Link);
1511 FreePool (CommandPacket->OutDataBuffer);
1512 FreePool (EraseBlkReq->CommandPacket.Cdb);
1513 FreePool (EraseBlkReq);
1514
1515 gBS->SignalEvent (Token->Event);
1516}
1517
1533 IN SCSI_DISK_DEV *ScsiDiskDevice,
1534 IN UINT64 Lba,
1535 IN UINTN Blocks,
1536 IN EFI_ERASE_BLOCK_TOKEN *Token OPTIONAL
1537 )
1538{
1539 EFI_SCSI_IO_PROTOCOL *ScsiIo;
1540 SCSI_ERASEBLK_REQUEST *EraseBlkReq;
1541 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
1543 EFI_STATUS Status;
1544 EFI_STATUS ReturnStatus;
1545 UINT8 *Cdb;
1546 UINT32 MaxLbaCnt;
1547 UINT32 MaxBlkDespCnt;
1548 UINT32 BlkDespCnt;
1549 UINT16 UnmapParamListLen;
1550 VOID *UnmapParamList;
1551 EFI_EVENT AsyncUnmapEvent;
1552 EFI_TPL OldTpl;
1553
1554 ScsiIo = ScsiDiskDevice->ScsiIo;
1555 MaxLbaCnt = ScsiDiskDevice->UnmapInfo.MaxLbaCnt;
1556 MaxBlkDespCnt = ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt;
1557 EraseBlkReq = NULL;
1558 UnmapParamList = NULL;
1559 AsyncUnmapEvent = NULL;
1560 ReturnStatus = EFI_SUCCESS;
1561
1562 if (Blocks / (UINTN)MaxLbaCnt > MaxBlkDespCnt) {
1563 ReturnStatus = EFI_DEVICE_ERROR;
1564 goto Done;
1565 }
1566
1567 EraseBlkReq = AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST));
1568 if (EraseBlkReq == NULL) {
1569 ReturnStatus = EFI_DEVICE_ERROR;
1570 goto Done;
1571 }
1572
1573 EraseBlkReq->CommandPacket.Cdb = AllocateZeroPool (0xA);
1574 if (EraseBlkReq->CommandPacket.Cdb == NULL) {
1575 ReturnStatus = EFI_DEVICE_ERROR;
1576 goto Done;
1577 }
1578
1579 BlkDespCnt = (UINT32)((Blocks - 1) / MaxLbaCnt + 1);
1580 UnmapParamListLen = (UINT16)(sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER)
1581 + BlkDespCnt * sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP));
1582 UnmapParamList = AllocateZeroPool (UnmapParamListLen);
1583 if (UnmapParamList == NULL) {
1584 ReturnStatus = EFI_DEVICE_ERROR;
1585 goto Done;
1586 }
1587
1588 *((UINT16 *)UnmapParamList) = SwapBytes16 (UnmapParamListLen - 2);
1589 *((UINT16 *)UnmapParamList + 1) = SwapBytes16 (UnmapParamListLen - sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
1590
1591 BlkDespPtr = (EFI_SCSI_DISK_UNMAP_BLOCK_DESP *)((UINT8 *)UnmapParamList + sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
1592 while (Blocks > 0) {
1593 if (Blocks > MaxLbaCnt) {
1594 *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);
1595 *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 (MaxLbaCnt);
1596 Blocks -= MaxLbaCnt;
1597 Lba += MaxLbaCnt;
1598 } else {
1599 *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);
1600 *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 ((UINT32)Blocks);
1601 Blocks = 0;
1602 }
1603
1604 BlkDespPtr++;
1605 }
1606
1607 CommandPacket = &EraseBlkReq->CommandPacket;
1608 CommandPacket->Timeout = SCSI_DISK_TIMEOUT;
1609 CommandPacket->OutDataBuffer = UnmapParamList;
1610 CommandPacket->OutTransferLength = UnmapParamListLen;
1611 CommandPacket->CdbLength = 0xA;
1612 CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;
1613 //
1614 // Fill Cdb for UNMAP Command
1615 //
1616 Cdb = CommandPacket->Cdb;
1617 Cdb[0] = EFI_SCSI_OP_UNMAP;
1618 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 (UnmapParamListLen));
1619
1620 if ((Token != NULL) && (Token->Event != NULL)) {
1621 //
1622 // Non-blocking UNMAP request
1623 //
1624 Status = gBS->CreateEvent (
1625 EVT_NOTIFY_SIGNAL,
1626 TPL_NOTIFY,
1628 EraseBlkReq,
1629 &AsyncUnmapEvent
1630 );
1631 if (EFI_ERROR (Status)) {
1632 ReturnStatus = EFI_DEVICE_ERROR;
1633 goto Done;
1634 }
1635
1636 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1637 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &EraseBlkReq->Link);
1638 gBS->RestoreTPL (OldTpl);
1639
1640 EraseBlkReq->Token = Token;
1641
1642 Status = ScsiIo->ExecuteScsiCommand (
1643 ScsiIo,
1644 CommandPacket,
1645 AsyncUnmapEvent
1646 );
1647 if (EFI_ERROR (Status)) {
1648 ReturnStatus = EFI_DEVICE_ERROR;
1649
1650 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1651 RemoveEntryList (&EraseBlkReq->Link);
1652 gBS->RestoreTPL (OldTpl);
1653
1654 goto Done;
1655 } else {
1656 //
1657 // Directly return if the non-blocking UNMAP request is queued.
1658 //
1659 return EFI_SUCCESS;
1660 }
1661 } else {
1662 //
1663 // Blocking UNMAP request
1664 //
1665 Status = ScsiIo->ExecuteScsiCommand (
1666 ScsiIo,
1667 CommandPacket,
1668 NULL
1669 );
1670 if (EFI_ERROR (Status)) {
1671 ReturnStatus = EFI_DEVICE_ERROR;
1672 goto Done;
1673 }
1674 }
1675
1676 //
1677 // Only blocking UNMAP request will reach here.
1678 //
1679 Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
1680 if (EFI_ERROR (Status)) {
1681 DEBUG ((
1682 DEBUG_ERROR,
1683 "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1684 CommandPacket->HostAdapterStatus
1685 ));
1686
1687 ReturnStatus = EFI_DEVICE_ERROR;
1688 goto Done;
1689 }
1690
1691 Status = CheckTargetStatus (CommandPacket->TargetStatus);
1692 if (EFI_ERROR (Status)) {
1693 DEBUG ((
1694 DEBUG_ERROR,
1695 "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1696 CommandPacket->HostAdapterStatus
1697 ));
1698
1699 ReturnStatus = EFI_DEVICE_ERROR;
1700 goto Done;
1701 }
1702
1703Done:
1704 if (EraseBlkReq != NULL) {
1705 if (EraseBlkReq->CommandPacket.Cdb != NULL) {
1706 FreePool (EraseBlkReq->CommandPacket.Cdb);
1707 }
1708
1709 FreePool (EraseBlkReq);
1710 }
1711
1712 if (UnmapParamList != NULL) {
1713 FreePool (UnmapParamList);
1714 }
1715
1716 if (AsyncUnmapEvent != NULL) {
1717 gBS->CloseEvent (AsyncUnmapEvent);
1718 }
1719
1720 return ReturnStatus;
1721}
1722
1751EFIAPI
1754 IN UINT32 MediaId,
1755 IN EFI_LBA Lba,
1757 IN UINTN Size
1758 )
1759{
1760 SCSI_DISK_DEV *ScsiDiskDevice;
1761 EFI_BLOCK_IO_MEDIA *Media;
1762 EFI_STATUS Status;
1763 UINTN BlockSize;
1764 UINTN NumberOfBlocks;
1765 BOOLEAN MediaChange;
1766 EFI_TPL OldTpl;
1767
1768 MediaChange = FALSE;
1769 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1770 ScsiDiskDevice = SCSI_DISK_DEV_FROM_ERASEBLK (This);
1771
1772 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
1773 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1774 if (EFI_ERROR (Status)) {
1775 Status = EFI_DEVICE_ERROR;
1776 goto Done;
1777 }
1778
1779 if (MediaChange) {
1780 gBS->ReinstallProtocolInterface (
1781 ScsiDiskDevice->Handle,
1782 &gEfiBlockIoProtocolGuid,
1783 &ScsiDiskDevice->BlkIo,
1784 &ScsiDiskDevice->BlkIo
1785 );
1786 gBS->ReinstallProtocolInterface (
1787 ScsiDiskDevice->Handle,
1788 &gEfiBlockIo2ProtocolGuid,
1789 &ScsiDiskDevice->BlkIo2,
1790 &ScsiDiskDevice->BlkIo2
1791 );
1792 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1793 gBS->ReinstallProtocolInterface (
1794 ScsiDiskDevice->Handle,
1795 &gEfiEraseBlockProtocolGuid,
1796 &ScsiDiskDevice->EraseBlock,
1797 &ScsiDiskDevice->EraseBlock
1798 );
1799 }
1800
1801 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1802 gBS->ReinstallProtocolInterface (
1803 ScsiDiskDevice->Handle,
1804 &gEfiStorageSecurityCommandProtocolGuid,
1805 &ScsiDiskDevice->StorageSecurity,
1806 &ScsiDiskDevice->StorageSecurity
1807 );
1808 }
1809
1810 Status = EFI_MEDIA_CHANGED;
1811 goto Done;
1812 }
1813 }
1814
1815 //
1816 // Get the intrinsic block size
1817 //
1818 Media = ScsiDiskDevice->BlkIo.Media;
1819
1820 if (!(Media->MediaPresent)) {
1821 Status = EFI_NO_MEDIA;
1822 goto Done;
1823 }
1824
1825 if (MediaId != Media->MediaId) {
1826 Status = EFI_MEDIA_CHANGED;
1827 goto Done;
1828 }
1829
1830 if (Media->ReadOnly) {
1831 Status = EFI_WRITE_PROTECTED;
1832 goto Done;
1833 }
1834
1835 if (Size == 0) {
1836 if ((Token != NULL) && (Token->Event != NULL)) {
1837 Token->TransactionStatus = EFI_SUCCESS;
1838 gBS->SignalEvent (Token->Event);
1839 }
1840
1841 Status = EFI_SUCCESS;
1842 goto Done;
1843 }
1844
1845 BlockSize = Media->BlockSize;
1846 if ((Size % BlockSize) != 0) {
1847 Status = EFI_INVALID_PARAMETER;
1848 goto Done;
1849 }
1850
1851 NumberOfBlocks = Size / BlockSize;
1852 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1853 Status = EFI_INVALID_PARAMETER;
1854 goto Done;
1855 }
1856
1857 if ((Token != NULL) && (Token->Event != NULL)) {
1858 Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, Token);
1859 } else {
1860 Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, NULL);
1861 }
1862
1863Done:
1864 gBS->RestoreTPL (OldTpl);
1865 return Status;
1866}
1867
1935EFIAPI
1938 IN UINT32 MediaId OPTIONAL,
1939 IN UINT64 Timeout,
1940 IN UINT8 SecurityProtocolId,
1941 IN UINT16 SecurityProtocolSpecificData,
1942 IN UINTN PayloadBufferSize,
1943 OUT VOID *PayloadBuffer,
1944 OUT UINTN *PayloadTransferSize
1945 )
1946{
1947 SCSI_DISK_DEV *ScsiDiskDevice;
1948 EFI_BLOCK_IO_MEDIA *Media;
1949 EFI_STATUS Status;
1950 BOOLEAN MediaChange;
1951 EFI_TPL OldTpl;
1952 UINT8 SenseDataLength;
1953 UINT8 HostAdapterStatus;
1954 UINT8 TargetStatus;
1955 VOID *AlignedBuffer;
1956 BOOLEAN AlignedBufferAllocated;
1957
1958 AlignedBuffer = NULL;
1959 MediaChange = FALSE;
1960 AlignedBufferAllocated = FALSE;
1961 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1962 ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
1963 Media = ScsiDiskDevice->BlkIo.Media;
1964
1965 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
1966
1967 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
1968 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1969 if (EFI_ERROR (Status)) {
1970 Status = EFI_DEVICE_ERROR;
1971 goto Done;
1972 }
1973
1974 if (MediaChange) {
1975 gBS->ReinstallProtocolInterface (
1976 ScsiDiskDevice->Handle,
1977 &gEfiBlockIoProtocolGuid,
1978 &ScsiDiskDevice->BlkIo,
1979 &ScsiDiskDevice->BlkIo
1980 );
1981 gBS->ReinstallProtocolInterface (
1982 ScsiDiskDevice->Handle,
1983 &gEfiBlockIo2ProtocolGuid,
1984 &ScsiDiskDevice->BlkIo2,
1985 &ScsiDiskDevice->BlkIo2
1986 );
1987 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1988 gBS->ReinstallProtocolInterface (
1989 ScsiDiskDevice->Handle,
1990 &gEfiEraseBlockProtocolGuid,
1991 &ScsiDiskDevice->EraseBlock,
1992 &ScsiDiskDevice->EraseBlock
1993 );
1994 }
1995
1996 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1997 gBS->ReinstallProtocolInterface (
1998 ScsiDiskDevice->Handle,
1999 &gEfiStorageSecurityCommandProtocolGuid,
2000 &ScsiDiskDevice->StorageSecurity,
2001 &ScsiDiskDevice->StorageSecurity
2002 );
2003 }
2004
2005 if (Media->MediaPresent) {
2006 Status = EFI_MEDIA_CHANGED;
2007 } else {
2008 Status = EFI_NO_MEDIA;
2009 }
2010
2011 goto Done;
2012 }
2013 }
2014
2015 //
2016 // Validate Media
2017 //
2018 if (!(Media->MediaPresent)) {
2019 Status = EFI_NO_MEDIA;
2020 goto Done;
2021 }
2022
2023 if ((MediaId != 0) && (MediaId != Media->MediaId)) {
2024 Status = EFI_MEDIA_CHANGED;
2025 goto Done;
2026 }
2027
2028 if (PayloadBufferSize != 0) {
2029 if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL)) {
2030 Status = EFI_INVALID_PARAMETER;
2031 goto Done;
2032 }
2033
2034 if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
2035 AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
2036 if (AlignedBuffer == NULL) {
2037 Status = EFI_OUT_OF_RESOURCES;
2038 goto Done;
2039 }
2040
2041 ZeroMem (AlignedBuffer, PayloadBufferSize);
2042 AlignedBufferAllocated = TRUE;
2043 } else {
2044 AlignedBuffer = PayloadBuffer;
2045 }
2046 }
2047
2049 ScsiDiskDevice->ScsiIo,
2050 Timeout,
2051 ScsiDiskDevice->SenseData,
2052 &SenseDataLength,
2053 &HostAdapterStatus,
2054 &TargetStatus,
2055 SecurityProtocolId,
2056 SecurityProtocolSpecificData,
2057 FALSE,
2058 PayloadBufferSize,
2059 AlignedBuffer,
2060 PayloadTransferSize
2061 );
2062 if (EFI_ERROR (Status)) {
2063 goto Done;
2064 }
2065
2066 if (AlignedBufferAllocated) {
2067 CopyMem (PayloadBuffer, AlignedBuffer, PayloadBufferSize);
2068 }
2069
2070 if (PayloadBufferSize < *PayloadTransferSize) {
2071 Status = EFI_WARN_BUFFER_TOO_SMALL;
2072 goto Done;
2073 }
2074
2075 Status = CheckHostAdapterStatus (HostAdapterStatus);
2076 if (EFI_ERROR (Status)) {
2077 goto Done;
2078 }
2079
2080 Status = CheckTargetStatus (TargetStatus);
2081 if (EFI_ERROR (Status)) {
2082 goto Done;
2083 }
2084
2085Done:
2086 if (AlignedBufferAllocated) {
2087 ZeroMem (AlignedBuffer, PayloadBufferSize);
2088 FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
2089 }
2090
2091 gBS->RestoreTPL (OldTpl);
2092 return Status;
2093}
2094
2153EFIAPI
2156 IN UINT32 MediaId OPTIONAL,
2157 IN UINT64 Timeout,
2158 IN UINT8 SecurityProtocolId,
2159 IN UINT16 SecurityProtocolSpecificData,
2160 IN UINTN PayloadBufferSize,
2161 OUT VOID *PayloadBuffer
2162 )
2163{
2164 SCSI_DISK_DEV *ScsiDiskDevice;
2165 EFI_BLOCK_IO_MEDIA *Media;
2166 EFI_STATUS Status;
2167 BOOLEAN MediaChange;
2168 EFI_TPL OldTpl;
2169 UINT8 SenseDataLength;
2170 UINT8 HostAdapterStatus;
2171 UINT8 TargetStatus;
2172 VOID *AlignedBuffer;
2173 BOOLEAN AlignedBufferAllocated;
2174
2175 AlignedBuffer = NULL;
2176 MediaChange = FALSE;
2177 AlignedBufferAllocated = FALSE;
2178 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2179 ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
2180 Media = ScsiDiskDevice->BlkIo.Media;
2181
2182 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2183
2184 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
2185 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
2186 if (EFI_ERROR (Status)) {
2187 Status = EFI_DEVICE_ERROR;
2188 goto Done;
2189 }
2190
2191 if (MediaChange) {
2192 gBS->ReinstallProtocolInterface (
2193 ScsiDiskDevice->Handle,
2194 &gEfiBlockIoProtocolGuid,
2195 &ScsiDiskDevice->BlkIo,
2196 &ScsiDiskDevice->BlkIo
2197 );
2198 gBS->ReinstallProtocolInterface (
2199 ScsiDiskDevice->Handle,
2200 &gEfiBlockIo2ProtocolGuid,
2201 &ScsiDiskDevice->BlkIo2,
2202 &ScsiDiskDevice->BlkIo2
2203 );
2204 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
2205 gBS->ReinstallProtocolInterface (
2206 ScsiDiskDevice->Handle,
2207 &gEfiEraseBlockProtocolGuid,
2208 &ScsiDiskDevice->EraseBlock,
2209 &ScsiDiskDevice->EraseBlock
2210 );
2211 }
2212
2213 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
2214 gBS->ReinstallProtocolInterface (
2215 ScsiDiskDevice->Handle,
2216 &gEfiStorageSecurityCommandProtocolGuid,
2217 &ScsiDiskDevice->StorageSecurity,
2218 &ScsiDiskDevice->StorageSecurity
2219 );
2220 }
2221
2222 if (Media->MediaPresent) {
2223 Status = EFI_MEDIA_CHANGED;
2224 } else {
2225 Status = EFI_NO_MEDIA;
2226 }
2227
2228 goto Done;
2229 }
2230 }
2231
2232 //
2233 // Validate Media
2234 //
2235 if (!(Media->MediaPresent)) {
2236 Status = EFI_NO_MEDIA;
2237 goto Done;
2238 }
2239
2240 if ((MediaId != 0) && (MediaId != Media->MediaId)) {
2241 Status = EFI_MEDIA_CHANGED;
2242 goto Done;
2243 }
2244
2245 if (Media->ReadOnly) {
2246 Status = EFI_WRITE_PROTECTED;
2247 goto Done;
2248 }
2249
2250 if (PayloadBufferSize != 0) {
2251 if (PayloadBuffer == NULL) {
2252 Status = EFI_INVALID_PARAMETER;
2253 goto Done;
2254 }
2255
2256 if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
2257 AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
2258 if (AlignedBuffer == NULL) {
2259 Status = EFI_OUT_OF_RESOURCES;
2260 goto Done;
2261 }
2262
2263 CopyMem (AlignedBuffer, PayloadBuffer, PayloadBufferSize);
2264 AlignedBufferAllocated = TRUE;
2265 } else {
2266 AlignedBuffer = PayloadBuffer;
2267 }
2268 }
2269
2271 ScsiDiskDevice->ScsiIo,
2272 Timeout,
2273 ScsiDiskDevice->SenseData,
2274 &SenseDataLength,
2275 &HostAdapterStatus,
2276 &TargetStatus,
2277 SecurityProtocolId,
2278 SecurityProtocolSpecificData,
2279 FALSE,
2280 PayloadBufferSize,
2281 AlignedBuffer
2282 );
2283 if (EFI_ERROR (Status)) {
2284 goto Done;
2285 }
2286
2287 Status = CheckHostAdapterStatus (HostAdapterStatus);
2288 if (EFI_ERROR (Status)) {
2289 goto Done;
2290 }
2291
2292 Status = CheckTargetStatus (TargetStatus);
2293 if (EFI_ERROR (Status)) {
2294 goto Done;
2295 }
2296
2297Done:
2298 if (AlignedBufferAllocated) {
2299 ZeroMem (AlignedBuffer, PayloadBufferSize);
2300 FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
2301 }
2302
2303 gBS->RestoreTPL (OldTpl);
2304 return Status;
2305}
2306
2320 IN SCSI_DISK_DEV *ScsiDiskDevice,
2321 IN BOOLEAN MustReadCapacity,
2322 OUT BOOLEAN *MediaChange
2323 )
2324{
2325 EFI_STATUS Status;
2326 EFI_SCSI_SENSE_DATA *SenseData;
2327 UINTN NumberOfSenseKeys;
2328 BOOLEAN NeedRetry;
2329 BOOLEAN NeedReadCapacity;
2330 UINT8 Retry;
2331 UINT8 MaxRetry;
2332 EFI_BLOCK_IO_MEDIA OldMedia;
2333 UINTN Action;
2334 EFI_EVENT TimeoutEvt;
2335
2336 Status = EFI_SUCCESS;
2337 SenseData = NULL;
2338 NumberOfSenseKeys = 0;
2339 Retry = 0;
2340 MaxRetry = 3;
2341 Action = ACTION_NO_ACTION;
2342 NeedReadCapacity = FALSE;
2343 *MediaChange = FALSE;
2344 TimeoutEvt = NULL;
2345
2346 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
2347
2348 Status = gBS->CreateEvent (
2349 EVT_TIMER,
2350 TPL_CALLBACK,
2351 NULL,
2352 NULL,
2353 &TimeoutEvt
2354 );
2355 if (EFI_ERROR (Status)) {
2356 return Status;
2357 }
2358
2359 Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS (120));
2360 if (EFI_ERROR (Status)) {
2361 goto EXIT;
2362 }
2363
2364 //
2365 // Sending Test_Unit cmd to poll device status.
2366 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
2367 // We limit the upper boundary to 120 seconds.
2368 //
2369 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
2370 Status = ScsiDiskTestUnitReady (
2371 ScsiDiskDevice,
2372 &NeedRetry,
2373 &SenseData,
2374 &NumberOfSenseKeys
2375 );
2376 if (!EFI_ERROR (Status)) {
2378 ScsiDiskDevice,
2379 SenseData,
2380 NumberOfSenseKeys,
2381 &Action
2382 );
2383 if (EFI_ERROR (Status)) {
2384 goto EXIT;
2385 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
2386 continue;
2387 } else {
2388 break;
2389 }
2390 } else {
2391 Retry++;
2392 if (!NeedRetry || (Retry >= MaxRetry)) {
2393 goto EXIT;
2394 }
2395 }
2396 }
2397
2398 if (EFI_ERROR (Status)) {
2399 goto EXIT;
2400 }
2401
2402 //
2403 // ACTION_NO_ACTION: need not read capacity
2404 // other action code: need read capacity
2405 //
2406 if (Action == ACTION_READ_CAPACITY) {
2407 NeedReadCapacity = TRUE;
2408 }
2409
2410 //
2411 // READ_CAPACITY command is not supported by any of the UFS WLUNs.
2412 //
2413 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
2414 NeedReadCapacity = FALSE;
2415 MustReadCapacity = FALSE;
2416 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
2417 }
2418
2419 //
2420 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
2421 // retrieve capacity via Read Capacity command
2422 //
2423 if (NeedReadCapacity || MustReadCapacity) {
2424 //
2425 // retrieve media information
2426 //
2427 for (Retry = 0; Retry < MaxRetry; Retry++) {
2428 Status = ScsiDiskReadCapacity (
2429 ScsiDiskDevice,
2430 &NeedRetry,
2431 &SenseData,
2432 &NumberOfSenseKeys
2433 );
2434 if (!EFI_ERROR (Status)) {
2435 //
2436 // analyze sense key to action
2437 //
2439 ScsiDiskDevice,
2440 SenseData,
2441 NumberOfSenseKeys,
2442 &Action
2443 );
2444 if (EFI_ERROR (Status)) {
2445 //
2446 // if Status is error, it may indicate crisis error,
2447 // so return without retry.
2448 //
2449 goto EXIT;
2450 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
2451 Retry = 0;
2452 continue;
2453 } else {
2454 break;
2455 }
2456 } else {
2457 Retry++;
2458 if (!NeedRetry || (Retry >= MaxRetry)) {
2459 goto EXIT;
2460 }
2461 }
2462 }
2463
2464 if (EFI_ERROR (Status)) {
2465 goto EXIT;
2466 }
2467 }
2468
2469 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
2470 //
2471 // Media change information got from the device
2472 //
2473 *MediaChange = TRUE;
2474 }
2475
2476 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
2477 *MediaChange = TRUE;
2478 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2479 }
2480
2481 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
2482 *MediaChange = TRUE;
2483 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2484 }
2485
2486 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
2487 *MediaChange = TRUE;
2488 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2489 }
2490
2491 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
2492 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
2493 //
2494 // when change from no media to media present, reset the MediaId to 1.
2495 //
2496 ScsiDiskDevice->BlkIo.Media->MediaId = 1;
2497 } else {
2498 //
2499 // when no media, reset the MediaId to zero.
2500 //
2501 ScsiDiskDevice->BlkIo.Media->MediaId = 0;
2502 }
2503
2504 *MediaChange = TRUE;
2505 }
2506
2507EXIT:
2508 if (TimeoutEvt != NULL) {
2509 gBS->CloseEvent (TimeoutEvt);
2510 }
2511
2512 return Status;
2513}
2514
2527 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
2528 OUT BOOLEAN *NeedRetry
2529 )
2530{
2531 UINT32 InquiryDataLength;
2532 UINT8 SenseDataLength;
2533 UINT8 HostAdapterStatus;
2534 UINT8 TargetStatus;
2535 EFI_SCSI_SENSE_DATA *SenseDataArray;
2536 UINTN NumberOfSenseKeys;
2537 EFI_STATUS Status;
2538 UINT8 MaxRetry;
2539 UINT8 Index;
2540 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
2541 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;
2542 UINTN PageLength;
2543
2544 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
2545 SenseDataLength = 0;
2546
2547 Status = ScsiInquiryCommand (
2548 ScsiDiskDevice->ScsiIo,
2549 SCSI_DISK_TIMEOUT,
2550 NULL,
2551 &SenseDataLength,
2552 &HostAdapterStatus,
2553 &TargetStatus,
2554 (VOID *)&(ScsiDiskDevice->InquiryData),
2555 &InquiryDataLength,
2556 FALSE
2557 );
2558 //
2559 // no need to check HostAdapterStatus and TargetStatus
2560 //
2561 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
2562 ParseInquiryData (ScsiDiskDevice);
2563
2564 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
2565 //
2566 // Check whether the device supports Block Limits VPD page (0xB0)
2567 //
2568 SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2569 if (SupportedVpdPages == NULL) {
2570 *NeedRetry = FALSE;
2571 return EFI_DEVICE_ERROR;
2572 }
2573
2574 ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2575 InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
2576 SenseDataLength = 0;
2577 Status = ScsiInquiryCommandEx (
2578 ScsiDiskDevice->ScsiIo,
2579 SCSI_DISK_TIMEOUT,
2580 NULL,
2581 &SenseDataLength,
2582 &HostAdapterStatus,
2583 &TargetStatus,
2584 (VOID *)SupportedVpdPages,
2585 &InquiryDataLength,
2586 TRUE,
2587 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2588 );
2589 if (!EFI_ERROR (Status)) {
2590 PageLength = (SupportedVpdPages->PageLength2 << 8)
2591 | SupportedVpdPages->PageLength1;
2592
2593 //
2594 // Sanity checks for coping with broken devices
2595 //
2596 if (PageLength > sizeof SupportedVpdPages->SupportedVpdPageList) {
2597 DEBUG ((
2598 DEBUG_WARN,
2599 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
2600 __func__,
2601 (UINT32)PageLength
2602 ));
2603 PageLength = 0;
2604 }
2605
2606 if ((PageLength > 0) &&
2607 (SupportedVpdPages->SupportedVpdPageList[0] !=
2608 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD))
2609 {
2610 DEBUG ((
2611 DEBUG_WARN,
2612 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2613 __func__,
2614 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2615 ));
2616 PageLength = 0;
2617 }
2618
2619 //
2620 // Locate the code for the Block Limits VPD page
2621 //
2622 for (Index = 0; Index < PageLength; Index++) {
2623 //
2624 // Sanity check
2625 //
2626 if ((Index > 0) &&
2627 (SupportedVpdPages->SupportedVpdPageList[Index] <=
2628 SupportedVpdPages->SupportedVpdPageList[Index - 1]))
2629 {
2630 DEBUG ((
2631 DEBUG_WARN,
2632 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2633 __func__,
2634 Index
2635 ));
2636 Index = 0;
2637 PageLength = 0;
2638 break;
2639 }
2640
2641 if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
2642 break;
2643 }
2644 }
2645
2646 //
2647 // Query the Block Limits VPD page
2648 //
2649 if (Index < PageLength) {
2650 BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2651 if (BlockLimits == NULL) {
2652 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2653 *NeedRetry = FALSE;
2654 return EFI_DEVICE_ERROR;
2655 }
2656
2657 ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2658 InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
2659 SenseDataLength = 0;
2660 Status = ScsiInquiryCommandEx (
2661 ScsiDiskDevice->ScsiIo,
2662 SCSI_DISK_TIMEOUT,
2663 NULL,
2664 &SenseDataLength,
2665 &HostAdapterStatus,
2666 &TargetStatus,
2667 (VOID *)BlockLimits,
2668 &InquiryDataLength,
2669 TRUE,
2670 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2671 );
2672 if (!EFI_ERROR (Status)) {
2673 ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
2674 (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
2675 BlockLimits->OptimalTransferLengthGranularity1;
2676
2677 ScsiDiskDevice->UnmapInfo.MaxLbaCnt =
2678 (BlockLimits->MaximumUnmapLbaCount4 << 24) |
2679 (BlockLimits->MaximumUnmapLbaCount3 << 16) |
2680 (BlockLimits->MaximumUnmapLbaCount2 << 8) |
2681 BlockLimits->MaximumUnmapLbaCount1;
2682 ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt =
2683 (BlockLimits->MaximumUnmapBlockDescriptorCount4 << 24) |
2684 (BlockLimits->MaximumUnmapBlockDescriptorCount3 << 16) |
2685 (BlockLimits->MaximumUnmapBlockDescriptorCount2 << 8) |
2686 BlockLimits->MaximumUnmapBlockDescriptorCount1;
2687 ScsiDiskDevice->EraseBlock.EraseLengthGranularity =
2688 (BlockLimits->OptimalUnmapGranularity4 << 24) |
2689 (BlockLimits->OptimalUnmapGranularity3 << 16) |
2690 (BlockLimits->OptimalUnmapGranularity2 << 8) |
2691 BlockLimits->OptimalUnmapGranularity1;
2692 if (BlockLimits->UnmapGranularityAlignmentValid != 0) {
2693 ScsiDiskDevice->UnmapInfo.GranularityAlignment =
2694 (BlockLimits->UnmapGranularityAlignment4 << 24) |
2695 (BlockLimits->UnmapGranularityAlignment3 << 16) |
2696 (BlockLimits->UnmapGranularityAlignment2 << 8) |
2697 BlockLimits->UnmapGranularityAlignment1;
2698 }
2699
2700 if (ScsiDiskDevice->EraseBlock.EraseLengthGranularity == 0) {
2701 //
2702 // A value of 0 indicates that the optimal unmap granularity is
2703 // not reported.
2704 //
2705 ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
2706 }
2707
2708 ScsiDiskDevice->BlockLimitsVpdSupported = TRUE;
2709 }
2710
2711 FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2712 }
2713 }
2714
2715 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2716 }
2717 }
2718
2719 if (!EFI_ERROR (Status)) {
2720 return EFI_SUCCESS;
2721 } else if (Status == EFI_NOT_READY) {
2722 *NeedRetry = TRUE;
2723 return EFI_DEVICE_ERROR;
2724 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2725 *NeedRetry = FALSE;
2726 return EFI_DEVICE_ERROR;
2727 }
2728
2729 //
2730 // go ahead to check HostAdapterStatus and TargetStatus
2731 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2732 //
2733
2734 Status = CheckHostAdapterStatus (HostAdapterStatus);
2735 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2736 *NeedRetry = TRUE;
2737 return EFI_DEVICE_ERROR;
2738 } else if (Status == EFI_DEVICE_ERROR) {
2739 //
2740 // reset the scsi channel
2741 //
2742 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2743 *NeedRetry = FALSE;
2744 return EFI_DEVICE_ERROR;
2745 }
2746
2747 Status = CheckTargetStatus (TargetStatus);
2748 if (Status == EFI_NOT_READY) {
2749 //
2750 // reset the scsi device
2751 //
2752 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2753 *NeedRetry = TRUE;
2754 return EFI_DEVICE_ERROR;
2755 } else if (Status == EFI_DEVICE_ERROR) {
2756 *NeedRetry = FALSE;
2757 return EFI_DEVICE_ERROR;
2758 }
2759
2760 //
2761 // if goes here, meant ScsiInquiryCommand() failed.
2762 // if ScsiDiskRequestSenseKeys() succeeds at last,
2763 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2764 //
2765 MaxRetry = 3;
2766 for (Index = 0; Index < MaxRetry; Index++) {
2767 Status = ScsiDiskRequestSenseKeys (
2768 ScsiDiskDevice,
2769 NeedRetry,
2770 &SenseDataArray,
2771 &NumberOfSenseKeys,
2772 TRUE
2773 );
2774 if (!EFI_ERROR (Status)) {
2775 *NeedRetry = TRUE;
2776 return EFI_DEVICE_ERROR;
2777 }
2778
2779 if (!*NeedRetry) {
2780 return EFI_DEVICE_ERROR;
2781 }
2782 }
2783
2784 //
2785 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2786 // set *NeedRetry = FALSE to avoid the outside caller try again.
2787 //
2788 *NeedRetry = FALSE;
2789 return EFI_DEVICE_ERROR;
2790}
2791
2810 IN SCSI_DISK_DEV *ScsiDiskDevice,
2811 OUT BOOLEAN *NeedRetry,
2812 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
2813 OUT UINTN *NumberOfSenseKeys
2814 )
2815{
2816 EFI_STATUS Status;
2817 UINT8 SenseDataLength;
2818 UINT8 HostAdapterStatus;
2819 UINT8 TargetStatus;
2820 UINT8 Index;
2821 UINT8 MaxRetry;
2822
2823 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2824 *NumberOfSenseKeys = 0;
2825
2826 //
2827 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2828 //
2829 Status = ScsiTestUnitReadyCommand (
2830 ScsiDiskDevice->ScsiIo,
2831 SCSI_DISK_TIMEOUT,
2832 ScsiDiskDevice->SenseData,
2833 &SenseDataLength,
2834 &HostAdapterStatus,
2835 &TargetStatus
2836 );
2837 //
2838 // no need to check HostAdapterStatus and TargetStatus
2839 //
2840 if (Status == EFI_NOT_READY) {
2841 *NeedRetry = TRUE;
2842 return EFI_DEVICE_ERROR;
2843 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2844 *NeedRetry = FALSE;
2845 return EFI_DEVICE_ERROR;
2846 }
2847
2848 //
2849 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2850 //
2851
2852 Status = CheckHostAdapterStatus (HostAdapterStatus);
2853 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2854 *NeedRetry = TRUE;
2855 return EFI_DEVICE_ERROR;
2856 } else if (Status == EFI_DEVICE_ERROR) {
2857 //
2858 // reset the scsi channel
2859 //
2860 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2861 *NeedRetry = FALSE;
2862 return EFI_DEVICE_ERROR;
2863 }
2864
2865 Status = CheckTargetStatus (TargetStatus);
2866 if (Status == EFI_NOT_READY) {
2867 //
2868 // reset the scsi device
2869 //
2870 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2871 *NeedRetry = TRUE;
2872 return EFI_DEVICE_ERROR;
2873 } else if (Status == EFI_DEVICE_ERROR) {
2874 *NeedRetry = FALSE;
2875 return EFI_DEVICE_ERROR;
2876 }
2877
2878 if (SenseDataLength != 0) {
2879 *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
2880 *SenseDataArray = ScsiDiskDevice->SenseData;
2881 return EFI_SUCCESS;
2882 }
2883
2884 MaxRetry = 3;
2885 for (Index = 0; Index < MaxRetry; Index++) {
2886 Status = ScsiDiskRequestSenseKeys (
2887 ScsiDiskDevice,
2888 NeedRetry,
2889 SenseDataArray,
2890 NumberOfSenseKeys,
2891 FALSE
2892 );
2893 if (!EFI_ERROR (Status)) {
2894 return EFI_SUCCESS;
2895 }
2896
2897 if (!*NeedRetry) {
2898 return EFI_DEVICE_ERROR;
2899 }
2900 }
2901
2902 //
2903 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2904 // set *NeedRetry = FALSE to avoid the outside caller try again.
2905 //
2906 *NeedRetry = FALSE;
2907 return EFI_DEVICE_ERROR;
2908}
2909
2924 OUT SCSI_DISK_DEV *ScsiDiskDevice,
2925 IN EFI_SCSI_SENSE_DATA *SenseData,
2926 IN UINTN NumberOfSenseKeys,
2927 OUT UINTN *Action
2928 )
2929{
2930 BOOLEAN RetryLater;
2931
2932 //
2933 // Default is to read capacity, unless..
2934 //
2935 *Action = ACTION_READ_CAPACITY;
2936
2937 if (NumberOfSenseKeys == 0) {
2938 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2939 *Action = ACTION_NO_ACTION;
2940 }
2941
2942 return EFI_SUCCESS;
2943 }
2944
2945 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
2946 //
2947 // No Sense Key returned from last submitted command
2948 //
2949 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2950 *Action = ACTION_NO_ACTION;
2951 }
2952
2953 return EFI_SUCCESS;
2954 }
2955
2956 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
2957 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
2958 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
2959 *Action = ACTION_NO_ACTION;
2960 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2961 return EFI_SUCCESS;
2962 }
2963
2964 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
2965 ScsiDiskDevice->BlkIo.Media->MediaId++;
2966 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2967 return EFI_SUCCESS;
2968 }
2969
2970 if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
2971 *Action = ACTION_RETRY_COMMAND_LATER;
2972 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2973 return EFI_SUCCESS;
2974 }
2975
2976 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
2977 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
2978 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2979 return EFI_DEVICE_ERROR;
2980 }
2981
2982 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
2983 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2984 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2985 return EFI_DEVICE_ERROR;
2986 }
2987
2988 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
2989 if (RetryLater) {
2990 *Action = ACTION_RETRY_COMMAND_LATER;
2991 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2992 return EFI_SUCCESS;
2993 }
2994
2995 *Action = ACTION_NO_ACTION;
2996 return EFI_DEVICE_ERROR;
2997 }
2998
2999 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
3000 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
3001 return EFI_SUCCESS;
3002}
3003
3018 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
3019 OUT BOOLEAN *NeedRetry,
3020 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
3021 OUT UINTN *NumberOfSenseKeys
3022 )
3023{
3024 UINT8 HostAdapterStatus;
3025 UINT8 TargetStatus;
3026 EFI_STATUS CommandStatus;
3027 EFI_STATUS Status;
3028 UINT8 Index;
3029 UINT8 MaxRetry;
3030 UINT8 SenseDataLength;
3031 UINT32 DataLength10;
3032 UINT32 DataLength16;
3033 EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
3034 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
3035
3036 CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3037 if (CapacityData10 == NULL) {
3038 *NeedRetry = FALSE;
3039 return EFI_DEVICE_ERROR;
3040 }
3041
3042 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3043 if (CapacityData16 == NULL) {
3044 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3045 *NeedRetry = FALSE;
3046 return EFI_DEVICE_ERROR;
3047 }
3048
3049 SenseDataLength = 0;
3050 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
3051 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
3052 ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3053 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3054
3055 *NumberOfSenseKeys = 0;
3056 *NeedRetry = FALSE;
3057
3058 //
3059 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
3060 // 16 byte command should be used to access large hard disk >2TB
3061 //
3062 CommandStatus = ScsiReadCapacityCommand (
3063 ScsiDiskDevice->ScsiIo,
3064 SCSI_DISK_TIMEOUT,
3065 NULL,
3066 &SenseDataLength,
3067 &HostAdapterStatus,
3068 &TargetStatus,
3069 (VOID *)CapacityData10,
3070 &DataLength10,
3071 FALSE
3072 );
3073
3074 ScsiDiskDevice->Cdb16Byte = FALSE;
3075 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
3076 (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff))
3077 {
3078 //
3079 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
3080 //
3081 ScsiDiskDevice->Cdb16Byte = TRUE;
3082 //
3083 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
3084 // and LowestAlignedLba
3085 //
3086 CommandStatus = ScsiReadCapacity16Command (
3087 ScsiDiskDevice->ScsiIo,
3088 SCSI_DISK_TIMEOUT,
3089 NULL,
3090 &SenseDataLength,
3091 &HostAdapterStatus,
3092 &TargetStatus,
3093 (VOID *)CapacityData16,
3094 &DataLength16,
3095 FALSE
3096 );
3097 }
3098
3099 //
3100 // no need to check HostAdapterStatus and TargetStatus
3101 //
3102 if (CommandStatus == EFI_SUCCESS) {
3103 GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
3104 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3105 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3106 return EFI_SUCCESS;
3107 }
3108
3109 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3110 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3111
3112 if (CommandStatus == EFI_NOT_READY) {
3113 *NeedRetry = TRUE;
3114 return EFI_DEVICE_ERROR;
3115 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
3116 *NeedRetry = FALSE;
3117 return EFI_DEVICE_ERROR;
3118 }
3119
3120 //
3121 // go ahead to check HostAdapterStatus and TargetStatus
3122 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3123 //
3124
3125 Status = CheckHostAdapterStatus (HostAdapterStatus);
3126 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3127 *NeedRetry = TRUE;
3128 return EFI_DEVICE_ERROR;
3129 } else if (Status == EFI_DEVICE_ERROR) {
3130 //
3131 // reset the scsi channel
3132 //
3133 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3134 *NeedRetry = FALSE;
3135 return EFI_DEVICE_ERROR;
3136 }
3137
3138 Status = CheckTargetStatus (TargetStatus);
3139 if (Status == EFI_NOT_READY) {
3140 //
3141 // reset the scsi device
3142 //
3143 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3144 *NeedRetry = TRUE;
3145 return EFI_DEVICE_ERROR;
3146 } else if (Status == EFI_DEVICE_ERROR) {
3147 *NeedRetry = FALSE;
3148 return EFI_DEVICE_ERROR;
3149 }
3150
3151 //
3152 // if goes here, meant ScsiReadCapacityCommand() failed.
3153 // if ScsiDiskRequestSenseKeys() succeeds at last,
3154 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
3155 //
3156 MaxRetry = 3;
3157 for (Index = 0; Index < MaxRetry; Index++) {
3158 Status = ScsiDiskRequestSenseKeys (
3159 ScsiDiskDevice,
3160 NeedRetry,
3161 SenseDataArray,
3162 NumberOfSenseKeys,
3163 TRUE
3164 );
3165 if (!EFI_ERROR (Status)) {
3166 return EFI_SUCCESS;
3167 }
3168
3169 if (!*NeedRetry) {
3170 return EFI_DEVICE_ERROR;
3171 }
3172 }
3173
3174 //
3175 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
3176 // set *NeedRetry = FALSE to avoid the outside caller try again.
3177 //
3178 *NeedRetry = FALSE;
3179 return EFI_DEVICE_ERROR;
3180}
3181
3195 IN UINT8 HostAdapterStatus
3196 )
3197{
3198 switch (HostAdapterStatus) {
3199 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
3200 return EFI_SUCCESS;
3201
3202 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
3203 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
3204 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
3205 return EFI_TIMEOUT;
3206
3207 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
3208 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
3209 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
3210 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
3211 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
3212 return EFI_NOT_READY;
3213
3214 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
3215 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
3216 return EFI_DEVICE_ERROR;
3217
3218 default:
3219 return EFI_SUCCESS;
3220 }
3221}
3222
3235 IN UINT8 TargetStatus
3236 )
3237{
3238 switch (TargetStatus) {
3239 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
3240 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
3241 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
3242 return EFI_SUCCESS;
3243
3244 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
3245 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
3246 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
3247 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
3248 return EFI_NOT_READY;
3249
3250 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
3251 return EFI_DEVICE_ERROR;
3252
3253 default:
3254 return EFI_SUCCESS;
3255 }
3256}
3257
3277 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
3278 OUT BOOLEAN *NeedRetry,
3279 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
3280 OUT UINTN *NumberOfSenseKeys,
3281 IN BOOLEAN AskResetIfError
3282 )
3283{
3284 EFI_SCSI_SENSE_DATA *PtrSenseData;
3285 UINT8 SenseDataLength;
3286 BOOLEAN SenseReq;
3287 EFI_STATUS Status;
3288 EFI_STATUS FallStatus;
3289 UINT8 HostAdapterStatus;
3290 UINT8 TargetStatus;
3291
3292 FallStatus = EFI_SUCCESS;
3293 SenseDataLength = (UINT8)sizeof (EFI_SCSI_SENSE_DATA);
3294
3295 ZeroMem (
3296 ScsiDiskDevice->SenseData,
3297 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
3298 );
3299
3300 *NumberOfSenseKeys = 0;
3301 *SenseDataArray = ScsiDiskDevice->SenseData;
3302 Status = EFI_SUCCESS;
3303 PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
3304 if (PtrSenseData == NULL) {
3305 return EFI_DEVICE_ERROR;
3306 }
3307
3308 for (SenseReq = TRUE; SenseReq;) {
3309 ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
3310 Status = ScsiRequestSenseCommand (
3311 ScsiDiskDevice->ScsiIo,
3312 SCSI_DISK_TIMEOUT,
3313 PtrSenseData,
3314 &SenseDataLength,
3315 &HostAdapterStatus,
3316 &TargetStatus
3317 );
3318 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
3319 FallStatus = EFI_SUCCESS;
3320 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3321 *NeedRetry = TRUE;
3322 FallStatus = EFI_DEVICE_ERROR;
3323 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
3324 *NeedRetry = FALSE;
3325 FallStatus = EFI_DEVICE_ERROR;
3326 } else if (Status == EFI_DEVICE_ERROR) {
3327 if (AskResetIfError) {
3328 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3329 }
3330
3331 FallStatus = EFI_DEVICE_ERROR;
3332 }
3333
3334 if (EFI_ERROR (FallStatus)) {
3335 if (*NumberOfSenseKeys != 0) {
3336 *NeedRetry = FALSE;
3337 Status = EFI_SUCCESS;
3338 goto EXIT;
3339 } else {
3340 Status = EFI_DEVICE_ERROR;
3341 goto EXIT;
3342 }
3343 }
3344
3345 CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
3346 (*NumberOfSenseKeys) += 1;
3347
3348 //
3349 // no more sense key or number of sense keys exceeds predefined,
3350 // skip the loop.
3351 //
3352 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
3353 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber))
3354 {
3355 SenseReq = FALSE;
3356 }
3357 }
3358
3359EXIT:
3360 FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
3361 return Status;
3362}
3363
3372VOID
3374 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
3375 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
3377 )
3378{
3379 UINT8 *Ptr;
3380
3381 if (!ScsiDiskDevice->Cdb16Byte) {
3382 ScsiDiskDevice->BlkIo.Media->LastBlock = ((UINT32)Capacity10->LastLba3 << 24) |
3383 (Capacity10->LastLba2 << 16) |
3384 (Capacity10->LastLba1 << 8) |
3385 Capacity10->LastLba0;
3386
3387 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
3388 (Capacity10->BlockSize2 << 16) |
3389 (Capacity10->BlockSize1 << 8) |
3390 Capacity10->BlockSize0;
3391 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
3392 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;
3393 if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
3394 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;
3395 }
3396 } else {
3397 Ptr = (UINT8 *)&ScsiDiskDevice->BlkIo.Media->LastBlock;
3398 *Ptr++ = Capacity16->LastLba0;
3399 *Ptr++ = Capacity16->LastLba1;
3400 *Ptr++ = Capacity16->LastLba2;
3401 *Ptr++ = Capacity16->LastLba3;
3402 *Ptr++ = Capacity16->LastLba4;
3403 *Ptr++ = Capacity16->LastLba5;
3404 *Ptr++ = Capacity16->LastLba6;
3405 *Ptr = Capacity16->LastLba7;
3406
3407 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
3408 (Capacity16->BlockSize2 << 16) |
3409 (Capacity16->BlockSize1 << 8) |
3410 Capacity16->BlockSize0;
3411
3412 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
3413 Capacity16->LowestAlignLogic1;
3414 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);
3415 if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
3416 if (ScsiDiskDevice->BlkIo.Media->LastBlock > (UINT32)-1) {
3417 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)-1;
3418 } else {
3419 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;
3420 }
3421 }
3422 }
3423
3424 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
3425}
3426
3433VOID
3435 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
3436 )
3437{
3438 ScsiDiskDevice->FixedDevice = (BOOLEAN)((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
3439 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN)(!ScsiDiskDevice->FixedDevice);
3440}
3441
3456 IN SCSI_DISK_DEV *ScsiDiskDevice,
3457 OUT VOID *Buffer,
3458 IN EFI_LBA Lba,
3459 IN UINTN NumberOfBlocks
3460 )
3461{
3462 UINTN BlocksRemaining;
3463 UINT8 *PtrBuffer;
3464 UINT32 BlockSize;
3465 UINT32 ByteCount;
3466 UINT32 MaxBlock;
3467 UINT32 SectorCount;
3468 UINT32 NextSectorCount;
3469 UINT64 Timeout;
3470 EFI_STATUS Status;
3471 UINT8 Index;
3472 UINT8 MaxRetry;
3473 BOOLEAN NeedRetry;
3474
3475 Status = EFI_SUCCESS;
3476
3477 BlocksRemaining = NumberOfBlocks;
3478 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
3479
3480 //
3481 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3482 //
3483 if (!ScsiDiskDevice->Cdb16Byte) {
3484 MaxBlock = 0xFFFF;
3485 } else {
3486 MaxBlock = 0xFFFFFFFF;
3487 }
3488
3489 PtrBuffer = Buffer;
3490
3491 while (BlocksRemaining > 0) {
3492 if (BlocksRemaining <= MaxBlock) {
3493 if (!ScsiDiskDevice->Cdb16Byte) {
3494 SectorCount = (UINT16)BlocksRemaining;
3495 } else {
3496 SectorCount = (UINT32)BlocksRemaining;
3497 }
3498 } else {
3499 SectorCount = MaxBlock;
3500 }
3501
3502 ByteCount = SectorCount * BlockSize;
3503 //
3504 // |------------------------|-----------------|------------------|-----------------|
3505 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3506 // |------------------------|-----------------|------------------|-----------------|
3507 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3508 // |------------------------|-----------------|------------------|-----------------|
3509 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3510 // |------------------------|-----------------|------------------|-----------------|
3511 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3512 // |------------------------|-----------------|------------------|-----------------|
3513 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3514 // |------------------------|-----------------|------------------|-----------------|
3515 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3516 // |------------------------|-----------------|------------------|-----------------|
3517 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3518 // |------------------------|-----------------|------------------|-----------------|
3519 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3520 // |------------------------|-----------------|------------------|-----------------|
3521 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3522 // |------------------------|-----------------|------------------|-----------------|
3523 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3524 // |------------------------|-----------------|------------------|-----------------|
3525 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3526 // |------------------------|-----------------|------------------|-----------------|
3527 //
3528 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3529 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3530 // From the above table, we could know 2.1Mbytes per second is lowest one.
3531 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3532 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3533 // commands in the Standby/Idle mode.
3534 //
3535 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3536
3537 MaxRetry = 2;
3538 for (Index = 0; Index < MaxRetry; Index++) {
3539 if (!ScsiDiskDevice->Cdb16Byte) {
3540 Status = ScsiDiskRead10 (
3541 ScsiDiskDevice,
3542 &NeedRetry,
3543 Timeout,
3544 PtrBuffer,
3545 &ByteCount,
3546 (UINT32)Lba,
3547 SectorCount
3548 );
3549 } else {
3550 Status = ScsiDiskRead16 (
3551 ScsiDiskDevice,
3552 &NeedRetry,
3553 Timeout,
3554 PtrBuffer,
3555 &ByteCount,
3556 Lba,
3557 SectorCount
3558 );
3559 }
3560
3561 if (!EFI_ERROR (Status)) {
3562 break;
3563 }
3564
3565 if (!NeedRetry) {
3566 return EFI_DEVICE_ERROR;
3567 }
3568
3569 //
3570 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
3571 // lowered ByteCount on output, we must make sure that we lower
3572 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3573 // it is invalid to request more sectors in the CDB than the entire
3574 // transfer (ie. ByteCount) can carry.
3575 //
3576 // In addition, ByteCount is only expected to go down, or stay unchanged.
3577 // Therefore we don't need to update Timeout: the original timeout should
3578 // accommodate shorter transfers too.
3579 //
3580 NextSectorCount = ByteCount / BlockSize;
3581 if (NextSectorCount < SectorCount) {
3582 SectorCount = NextSectorCount;
3583 //
3584 // Account for any rounding down.
3585 //
3586 ByteCount = SectorCount * BlockSize;
3587 }
3588 }
3589
3590 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
3591 return EFI_DEVICE_ERROR;
3592 }
3593
3594 //
3595 // actual transferred sectors
3596 //
3597 SectorCount = ByteCount / BlockSize;
3598
3599 Lba += SectorCount;
3600 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3601 BlocksRemaining -= SectorCount;
3602 }
3603
3604 return EFI_SUCCESS;
3605}
3606
3621 IN SCSI_DISK_DEV *ScsiDiskDevice,
3622 IN VOID *Buffer,
3623 IN EFI_LBA Lba,
3624 IN UINTN NumberOfBlocks
3625 )
3626{
3627 UINTN BlocksRemaining;
3628 UINT8 *PtrBuffer;
3629 UINT32 BlockSize;
3630 UINT32 ByteCount;
3631 UINT32 MaxBlock;
3632 UINT32 SectorCount;
3633 UINT32 NextSectorCount;
3634 UINT64 Timeout;
3635 EFI_STATUS Status;
3636 UINT8 Index;
3637 UINT8 MaxRetry;
3638 BOOLEAN NeedRetry;
3639
3640 Status = EFI_SUCCESS;
3641
3642 BlocksRemaining = NumberOfBlocks;
3643 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
3644
3645 //
3646 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3647 //
3648 if (!ScsiDiskDevice->Cdb16Byte) {
3649 MaxBlock = 0xFFFF;
3650 } else {
3651 MaxBlock = 0xFFFFFFFF;
3652 }
3653
3654 PtrBuffer = Buffer;
3655
3656 while (BlocksRemaining > 0) {
3657 if (BlocksRemaining <= MaxBlock) {
3658 if (!ScsiDiskDevice->Cdb16Byte) {
3659 SectorCount = (UINT16)BlocksRemaining;
3660 } else {
3661 SectorCount = (UINT32)BlocksRemaining;
3662 }
3663 } else {
3664 SectorCount = MaxBlock;
3665 }
3666
3667 ByteCount = SectorCount * BlockSize;
3668 //
3669 // |------------------------|-----------------|------------------|-----------------|
3670 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3671 // |------------------------|-----------------|------------------|-----------------|
3672 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3673 // |------------------------|-----------------|------------------|-----------------|
3674 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3675 // |------------------------|-----------------|------------------|-----------------|
3676 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3677 // |------------------------|-----------------|------------------|-----------------|
3678 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3679 // |------------------------|-----------------|------------------|-----------------|
3680 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3681 // |------------------------|-----------------|------------------|-----------------|
3682 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3683 // |------------------------|-----------------|------------------|-----------------|
3684 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3685 // |------------------------|-----------------|------------------|-----------------|
3686 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3687 // |------------------------|-----------------|------------------|-----------------|
3688 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3689 // |------------------------|-----------------|------------------|-----------------|
3690 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3691 // |------------------------|-----------------|------------------|-----------------|
3692 //
3693 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3694 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3695 // From the above table, we could know 2.1Mbytes per second is lowest one.
3696 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3697 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3698 // commands in the Standby/Idle mode.
3699 //
3700 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3701 MaxRetry = 2;
3702 for (Index = 0; Index < MaxRetry; Index++) {
3703 if (!ScsiDiskDevice->Cdb16Byte) {
3704 Status = ScsiDiskWrite10 (
3705 ScsiDiskDevice,
3706 &NeedRetry,
3707 Timeout,
3708 PtrBuffer,
3709 &ByteCount,
3710 (UINT32)Lba,
3711 SectorCount
3712 );
3713 } else {
3714 Status = ScsiDiskWrite16 (
3715 ScsiDiskDevice,
3716 &NeedRetry,
3717 Timeout,
3718 PtrBuffer,
3719 &ByteCount,
3720 Lba,
3721 SectorCount
3722 );
3723 }
3724
3725 if (!EFI_ERROR (Status)) {
3726 break;
3727 }
3728
3729 if (!NeedRetry) {
3730 return EFI_DEVICE_ERROR;
3731 }
3732
3733 //
3734 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3735 // has lowered ByteCount on output, we must make sure that we lower
3736 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3737 // it is invalid to request more sectors in the CDB than the entire
3738 // transfer (ie. ByteCount) can carry.
3739 //
3740 // In addition, ByteCount is only expected to go down, or stay unchanged.
3741 // Therefore we don't need to update Timeout: the original timeout should
3742 // accommodate shorter transfers too.
3743 //
3744 NextSectorCount = ByteCount / BlockSize;
3745 if (NextSectorCount < SectorCount) {
3746 SectorCount = NextSectorCount;
3747 //
3748 // Account for any rounding down.
3749 //
3750 ByteCount = SectorCount * BlockSize;
3751 }
3752 }
3753
3754 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
3755 return EFI_DEVICE_ERROR;
3756 }
3757
3758 //
3759 // actual transferred sectors
3760 //
3761 SectorCount = ByteCount / BlockSize;
3762
3763 Lba += SectorCount;
3764 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3765 BlocksRemaining -= SectorCount;
3766 }
3767
3768 return EFI_SUCCESS;
3769}
3770
3788 IN SCSI_DISK_DEV *ScsiDiskDevice,
3789 OUT VOID *Buffer,
3790 IN EFI_LBA Lba,
3791 IN UINTN NumberOfBlocks,
3792 IN EFI_BLOCK_IO2_TOKEN *Token
3793 )
3794{
3795 UINTN BlocksRemaining;
3796 UINT8 *PtrBuffer;
3797 UINT32 BlockSize;
3798 UINT32 ByteCount;
3799 UINT32 MaxBlock;
3800 UINT32 SectorCount;
3801 UINT64 Timeout;
3802 SCSI_BLKIO2_REQUEST *BlkIo2Req;
3803 EFI_STATUS Status;
3804 EFI_TPL OldTpl;
3805
3806 if ((Token == NULL) || (Token->Event == NULL)) {
3807 return EFI_INVALID_PARAMETER;
3808 }
3809
3810 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
3811 if (BlkIo2Req == NULL) {
3812 return EFI_OUT_OF_RESOURCES;
3813 }
3814
3815 BlkIo2Req->Token = Token;
3816
3817 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3818 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
3819 gBS->RestoreTPL (OldTpl);
3820
3821 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
3822
3823 Status = EFI_SUCCESS;
3824
3825 BlocksRemaining = NumberOfBlocks;
3826 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
3827
3828 //
3829 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3830 // Command
3831 //
3832 if (!ScsiDiskDevice->Cdb16Byte) {
3833 MaxBlock = 0xFFFF;
3834 } else {
3835 MaxBlock = 0xFFFFFFFF;
3836 }
3837
3838 PtrBuffer = Buffer;
3839
3840 while (BlocksRemaining > 0) {
3841 if (BlocksRemaining <= MaxBlock) {
3842 if (!ScsiDiskDevice->Cdb16Byte) {
3843 SectorCount = (UINT16)BlocksRemaining;
3844 } else {
3845 SectorCount = (UINT32)BlocksRemaining;
3846 }
3847 } else {
3848 SectorCount = MaxBlock;
3849 }
3850
3851 ByteCount = SectorCount * BlockSize;
3852 //
3853 // |------------------------|-----------------|------------------|-----------------|
3854 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3855 // |------------------------|-----------------|------------------|-----------------|
3856 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3857 // |------------------------|-----------------|------------------|-----------------|
3858 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3859 // |------------------------|-----------------|------------------|-----------------|
3860 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3861 // |------------------------|-----------------|------------------|-----------------|
3862 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3863 // |------------------------|-----------------|------------------|-----------------|
3864 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3865 // |------------------------|-----------------|------------------|-----------------|
3866 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3867 // |------------------------|-----------------|------------------|-----------------|
3868 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3869 // |------------------------|-----------------|------------------|-----------------|
3870 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3871 // |------------------------|-----------------|------------------|-----------------|
3872 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3873 // |------------------------|-----------------|------------------|-----------------|
3874 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3875 // |------------------------|-----------------|------------------|-----------------|
3876 //
3877 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3878 // we have to use the lowest transfer rate to calculate the possible
3879 // maximum timeout value for each operation.
3880 // From the above table, we could know 2.1Mbytes per second is lowest one.
3881 // The timeout value is rounded up to nearest integer and here an additional
3882 // 30s is added to follow ATA spec in which it mentioned that the device
3883 // may take up to 30s to respond commands in the Standby/Idle mode.
3884 //
3885 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3886
3887 if (!ScsiDiskDevice->Cdb16Byte) {
3888 Status = ScsiDiskAsyncRead10 (
3889 ScsiDiskDevice,
3890 Timeout,
3891 0,
3892 PtrBuffer,
3893 ByteCount,
3894 (UINT32)Lba,
3895 SectorCount,
3896 BlkIo2Req,
3897 Token
3898 );
3899 } else {
3900 Status = ScsiDiskAsyncRead16 (
3901 ScsiDiskDevice,
3902 Timeout,
3903 0,
3904 PtrBuffer,
3905 ByteCount,
3906 Lba,
3907 SectorCount,
3908 BlkIo2Req,
3909 Token
3910 );
3911 }
3912
3913 if (EFI_ERROR (Status)) {
3914 //
3915 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3916 // length of a SCSI I/O command is too large.
3917 // In this case, we retry sending the SCSI command with a data length
3918 // half of its previous value.
3919 //
3920 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
3921 if ((MaxBlock > 1) && (SectorCount > 1)) {
3922 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
3923 continue;
3924 }
3925 }
3926
3927 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3928 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3929 //
3930 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3931 // SCSI sub-task running. Otherwise, it will be freed in the callback
3932 // function ScsiDiskNotify().
3933 //
3934 RemoveEntryList (&BlkIo2Req->Link);
3935 FreePool (BlkIo2Req);
3936 BlkIo2Req = NULL;
3937 gBS->RestoreTPL (OldTpl);
3938
3939 //
3940 // It is safe to return error status to the caller, since there is no
3941 // previous SCSI sub-task executing.
3942 //
3943 Status = EFI_DEVICE_ERROR;
3944 goto Done;
3945 } else {
3946 gBS->RestoreTPL (OldTpl);
3947
3948 //
3949 // There are previous SCSI commands still running, EFI_SUCCESS should
3950 // be returned to make sure that the caller does not free resources
3951 // still using by these SCSI commands.
3952 //
3953 Status = EFI_SUCCESS;
3954 goto Done;
3955 }
3956 }
3957
3958 //
3959 // Sectors submitted for transfer
3960 //
3961 SectorCount = ByteCount / BlockSize;
3962
3963 Lba += SectorCount;
3964 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3965 BlocksRemaining -= SectorCount;
3966 }
3967
3968 Status = EFI_SUCCESS;
3969
3970Done:
3971 if (BlkIo2Req != NULL) {
3972 BlkIo2Req->LastScsiRW = TRUE;
3973
3974 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3975 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3976 RemoveEntryList (&BlkIo2Req->Link);
3977 FreePool (BlkIo2Req);
3978 BlkIo2Req = NULL;
3979
3980 gBS->SignalEvent (Token->Event);
3981 }
3982
3983 gBS->RestoreTPL (OldTpl);
3984 }
3985
3986 return Status;
3987}
3988
4006 IN SCSI_DISK_DEV *ScsiDiskDevice,
4007 IN VOID *Buffer,
4008 IN EFI_LBA Lba,
4009 IN UINTN NumberOfBlocks,
4010 IN EFI_BLOCK_IO2_TOKEN *Token
4011 )
4012{
4013 UINTN BlocksRemaining;
4014 UINT8 *PtrBuffer;
4015 UINT32 BlockSize;
4016 UINT32 ByteCount;
4017 UINT32 MaxBlock;
4018 UINT32 SectorCount;
4019 UINT64 Timeout;
4020 SCSI_BLKIO2_REQUEST *BlkIo2Req;
4021 EFI_STATUS Status;
4022 EFI_TPL OldTpl;
4023
4024 if ((Token == NULL) || (Token->Event == NULL)) {
4025 return EFI_INVALID_PARAMETER;
4026 }
4027
4028 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
4029 if (BlkIo2Req == NULL) {
4030 return EFI_OUT_OF_RESOURCES;
4031 }
4032
4033 BlkIo2Req->Token = Token;
4034
4035 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4036 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
4037 gBS->RestoreTPL (OldTpl);
4038
4039 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
4040
4041 Status = EFI_SUCCESS;
4042
4043 BlocksRemaining = NumberOfBlocks;
4044 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
4045
4046 //
4047 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
4048 // Command
4049 //
4050 if (!ScsiDiskDevice->Cdb16Byte) {
4051 MaxBlock = 0xFFFF;
4052 } else {
4053 MaxBlock = 0xFFFFFFFF;
4054 }
4055
4056 PtrBuffer = Buffer;
4057
4058 while (BlocksRemaining > 0) {
4059 if (BlocksRemaining <= MaxBlock) {
4060 if (!ScsiDiskDevice->Cdb16Byte) {
4061 SectorCount = (UINT16)BlocksRemaining;
4062 } else {
4063 SectorCount = (UINT32)BlocksRemaining;
4064 }
4065 } else {
4066 SectorCount = MaxBlock;
4067 }
4068
4069 ByteCount = SectorCount * BlockSize;
4070 //
4071 // |------------------------|-----------------|------------------|-----------------|
4072 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
4073 // |------------------------|-----------------|------------------|-----------------|
4074 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
4075 // |------------------------|-----------------|------------------|-----------------|
4076 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
4077 // |------------------------|-----------------|------------------|-----------------|
4078 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
4079 // |------------------------|-----------------|------------------|-----------------|
4080 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
4081 // |------------------------|-----------------|------------------|-----------------|
4082 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
4083 // |------------------------|-----------------|------------------|-----------------|
4084 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
4085 // |------------------------|-----------------|------------------|-----------------|
4086 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
4087 // |------------------------|-----------------|------------------|-----------------|
4088 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
4089 // |------------------------|-----------------|------------------|-----------------|
4090 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
4091 // |------------------------|-----------------|------------------|-----------------|
4092 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
4093 // |------------------------|-----------------|------------------|-----------------|
4094 //
4095 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
4096 // we have to use the lowest transfer rate to calculate the possible
4097 // maximum timeout value for each operation.
4098 // From the above table, we could know 2.1Mbytes per second is lowest one.
4099 // The timeout value is rounded up to nearest integer and here an additional
4100 // 30s is added to follow ATA spec in which it mentioned that the device
4101 // may take up to 30s to respond commands in the Standby/Idle mode.
4102 //
4103 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
4104
4105 if (!ScsiDiskDevice->Cdb16Byte) {
4106 Status = ScsiDiskAsyncWrite10 (
4107 ScsiDiskDevice,
4108 Timeout,
4109 0,
4110 PtrBuffer,
4111 ByteCount,
4112 (UINT32)Lba,
4113 SectorCount,
4114 BlkIo2Req,
4115 Token
4116 );
4117 } else {
4118 Status = ScsiDiskAsyncWrite16 (
4119 ScsiDiskDevice,
4120 Timeout,
4121 0,
4122 PtrBuffer,
4123 ByteCount,
4124 Lba,
4125 SectorCount,
4126 BlkIo2Req,
4127 Token
4128 );
4129 }
4130
4131 if (EFI_ERROR (Status)) {
4132 //
4133 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
4134 // length of a SCSI I/O command is too large.
4135 // In this case, we retry sending the SCSI command with a data length
4136 // half of its previous value.
4137 //
4138 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
4139 if ((MaxBlock > 1) && (SectorCount > 1)) {
4140 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
4141 continue;
4142 }
4143 }
4144
4145 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4146 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
4147 //
4148 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
4149 // SCSI sub-task running. Otherwise, it will be freed in the callback
4150 // function ScsiDiskNotify().
4151 //
4152 RemoveEntryList (&BlkIo2Req->Link);
4153 FreePool (BlkIo2Req);
4154 BlkIo2Req = NULL;
4155 gBS->RestoreTPL (OldTpl);
4156
4157 //
4158 // It is safe to return error status to the caller, since there is no
4159 // previous SCSI sub-task executing.
4160 //
4161 Status = EFI_DEVICE_ERROR;
4162 goto Done;
4163 } else {
4164 gBS->RestoreTPL (OldTpl);
4165
4166 //
4167 // There are previous SCSI commands still running, EFI_SUCCESS should
4168 // be returned to make sure that the caller does not free resources
4169 // still using by these SCSI commands.
4170 //
4171 Status = EFI_SUCCESS;
4172 goto Done;
4173 }
4174 }
4175
4176 //
4177 // Sectors submitted for transfer
4178 //
4179 SectorCount = ByteCount / BlockSize;
4180
4181 Lba += SectorCount;
4182 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
4183 BlocksRemaining -= SectorCount;
4184 }
4185
4186 Status = EFI_SUCCESS;
4187
4188Done:
4189 if (BlkIo2Req != NULL) {
4190 BlkIo2Req->LastScsiRW = TRUE;
4191
4192 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4193 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
4194 RemoveEntryList (&BlkIo2Req->Link);
4195 FreePool (BlkIo2Req);
4196 BlkIo2Req = NULL;
4197
4198 gBS->SignalEvent (Token->Event);
4199 }
4200
4201 gBS->RestoreTPL (OldTpl);
4202 }
4203
4204 return Status;
4205}
4206
4222 IN SCSI_DISK_DEV *ScsiDiskDevice,
4223 OUT BOOLEAN *NeedRetry,
4224 IN UINT64 Timeout,
4225 OUT UINT8 *DataBuffer,
4226 IN OUT UINT32 *DataLength,
4227 IN UINT32 StartLba,
4228 IN UINT32 SectorCount
4229 )
4230{
4231 UINT8 SenseDataLength;
4232 EFI_STATUS Status;
4233 EFI_STATUS ReturnStatus;
4234 UINT8 HostAdapterStatus;
4235 UINT8 TargetStatus;
4236 UINTN Action;
4237
4238 //
4239 // Implement a backoff algorithm to resolve some compatibility issues that
4240 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4241 // big data in a single operation.
4242 // This algorithm will at first try to execute original request. If the request fails
4243 // with media error sense data or else, it will reduce the transfer length to half and
4244 // try again till the operation succeeds or fails with one sector transfer length.
4245 //
4246BackOff:
4247 *NeedRetry = FALSE;
4248 Action = ACTION_NO_ACTION;
4249 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4250 ReturnStatus = ScsiRead10Command (
4251 ScsiDiskDevice->ScsiIo,
4252 Timeout,
4253 ScsiDiskDevice->SenseData,
4254 &SenseDataLength,
4255 &HostAdapterStatus,
4256 &TargetStatus,
4257 DataBuffer,
4258 DataLength,
4259 StartLba,
4260 SectorCount
4261 );
4262
4263 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4264 *NeedRetry = TRUE;
4265 return EFI_DEVICE_ERROR;
4266 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4267 *NeedRetry = FALSE;
4268 return ReturnStatus;
4269 }
4270
4271 //
4272 // go ahead to check HostAdapterStatus and TargetStatus
4273 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4274 //
4275 Status = CheckHostAdapterStatus (HostAdapterStatus);
4276 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4277 *NeedRetry = TRUE;
4278 return EFI_DEVICE_ERROR;
4279 } else if (Status == EFI_DEVICE_ERROR) {
4280 //
4281 // reset the scsi channel
4282 //
4283 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4284 *NeedRetry = FALSE;
4285 return EFI_DEVICE_ERROR;
4286 }
4287
4288 Status = CheckTargetStatus (TargetStatus);
4289 if (Status == EFI_NOT_READY) {
4290 //
4291 // reset the scsi device
4292 //
4293 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4294 *NeedRetry = TRUE;
4295 return EFI_DEVICE_ERROR;
4296 } else if (Status == EFI_DEVICE_ERROR) {
4297 *NeedRetry = FALSE;
4298 return EFI_DEVICE_ERROR;
4299 }
4300
4301 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4302 DEBUG ((DEBUG_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
4303 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4304 if (Action == ACTION_RETRY_COMMAND_LATER) {
4305 *NeedRetry = TRUE;
4306 return EFI_DEVICE_ERROR;
4307 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4308 if (SectorCount <= 1) {
4309 //
4310 // Jump out if the operation still fails with one sector transfer length.
4311 //
4312 *NeedRetry = FALSE;
4313 return EFI_DEVICE_ERROR;
4314 }
4315
4316 //
4317 // Try again with half length if the sense data shows we need to retry.
4318 //
4319 SectorCount >>= 1;
4320 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4321 goto BackOff;
4322 } else {
4323 *NeedRetry = FALSE;
4324 return EFI_DEVICE_ERROR;
4325 }
4326 }
4327
4328 return ReturnStatus;
4329}
4330
4347 IN SCSI_DISK_DEV *ScsiDiskDevice,
4348 OUT BOOLEAN *NeedRetry,
4349 IN UINT64 Timeout,
4350 IN UINT8 *DataBuffer,
4351 IN OUT UINT32 *DataLength,
4352 IN UINT32 StartLba,
4353 IN UINT32 SectorCount
4354 )
4355{
4356 EFI_STATUS Status;
4357 EFI_STATUS ReturnStatus;
4358 UINT8 SenseDataLength;
4359 UINT8 HostAdapterStatus;
4360 UINT8 TargetStatus;
4361 UINTN Action;
4362
4363 //
4364 // Implement a backoff algorithm to resolve some compatibility issues that
4365 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4366 // big data in a single operation.
4367 // This algorithm will at first try to execute original request. If the request fails
4368 // with media error sense data or else, it will reduce the transfer length to half and
4369 // try again till the operation succeeds or fails with one sector transfer length.
4370 //
4371BackOff:
4372 *NeedRetry = FALSE;
4373 Action = ACTION_NO_ACTION;
4374 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4375 ReturnStatus = ScsiWrite10Command (
4376 ScsiDiskDevice->ScsiIo,
4377 Timeout,
4378 ScsiDiskDevice->SenseData,
4379 &SenseDataLength,
4380 &HostAdapterStatus,
4381 &TargetStatus,
4382 DataBuffer,
4383 DataLength,
4384 StartLba,
4385 SectorCount
4386 );
4387 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4388 *NeedRetry = TRUE;
4389 return EFI_DEVICE_ERROR;
4390 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4391 *NeedRetry = FALSE;
4392 return ReturnStatus;
4393 }
4394
4395 //
4396 // go ahead to check HostAdapterStatus and TargetStatus
4397 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4398 //
4399 Status = CheckHostAdapterStatus (HostAdapterStatus);
4400 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4401 *NeedRetry = TRUE;
4402 return EFI_DEVICE_ERROR;
4403 } else if (Status == EFI_DEVICE_ERROR) {
4404 //
4405 // reset the scsi channel
4406 //
4407 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4408 *NeedRetry = FALSE;
4409 return EFI_DEVICE_ERROR;
4410 }
4411
4412 Status = CheckTargetStatus (TargetStatus);
4413 if (Status == EFI_NOT_READY) {
4414 //
4415 // reset the scsi device
4416 //
4417 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4418 *NeedRetry = TRUE;
4419 return EFI_DEVICE_ERROR;
4420 } else if (Status == EFI_DEVICE_ERROR) {
4421 *NeedRetry = FALSE;
4422 return EFI_DEVICE_ERROR;
4423 }
4424
4425 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4426 DEBUG ((DEBUG_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
4427 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4428 if (Action == ACTION_RETRY_COMMAND_LATER) {
4429 *NeedRetry = TRUE;
4430 return EFI_DEVICE_ERROR;
4431 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4432 if (SectorCount <= 1) {
4433 //
4434 // Jump out if the operation still fails with one sector transfer length.
4435 //
4436 *NeedRetry = FALSE;
4437 return EFI_DEVICE_ERROR;
4438 }
4439
4440 //
4441 // Try again with half length if the sense data shows we need to retry.
4442 //
4443 SectorCount >>= 1;
4444 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4445 goto BackOff;
4446 } else {
4447 *NeedRetry = FALSE;
4448 return EFI_DEVICE_ERROR;
4449 }
4450 }
4451
4452 return ReturnStatus;
4453}
4454
4470 IN SCSI_DISK_DEV *ScsiDiskDevice,
4471 OUT BOOLEAN *NeedRetry,
4472 IN UINT64 Timeout,
4473 OUT UINT8 *DataBuffer,
4474 IN OUT UINT32 *DataLength,
4475 IN UINT64 StartLba,
4476 IN UINT32 SectorCount
4477 )
4478{
4479 UINT8 SenseDataLength;
4480 EFI_STATUS Status;
4481 EFI_STATUS ReturnStatus;
4482 UINT8 HostAdapterStatus;
4483 UINT8 TargetStatus;
4484 UINTN Action;
4485
4486 //
4487 // Implement a backoff algorithm to resolve some compatibility issues that
4488 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4489 // big data in a single operation.
4490 // This algorithm will at first try to execute original request. If the request fails
4491 // with media error sense data or else, it will reduce the transfer length to half and
4492 // try again till the operation succeeds or fails with one sector transfer length.
4493 //
4494BackOff:
4495 *NeedRetry = FALSE;
4496 Action = ACTION_NO_ACTION;
4497 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4498 ReturnStatus = ScsiRead16Command (
4499 ScsiDiskDevice->ScsiIo,
4500 Timeout,
4501 ScsiDiskDevice->SenseData,
4502 &SenseDataLength,
4503 &HostAdapterStatus,
4504 &TargetStatus,
4505 DataBuffer,
4506 DataLength,
4507 StartLba,
4508 SectorCount
4509 );
4510 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4511 *NeedRetry = TRUE;
4512 return EFI_DEVICE_ERROR;
4513 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4514 *NeedRetry = FALSE;
4515 return ReturnStatus;
4516 }
4517
4518 //
4519 // go ahead to check HostAdapterStatus and TargetStatus
4520 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4521 //
4522 Status = CheckHostAdapterStatus (HostAdapterStatus);
4523 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4524 *NeedRetry = TRUE;
4525 return EFI_DEVICE_ERROR;
4526 } else if (Status == EFI_DEVICE_ERROR) {
4527 //
4528 // reset the scsi channel
4529 //
4530 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4531 *NeedRetry = FALSE;
4532 return EFI_DEVICE_ERROR;
4533 }
4534
4535 Status = CheckTargetStatus (TargetStatus);
4536 if (Status == EFI_NOT_READY) {
4537 //
4538 // reset the scsi device
4539 //
4540 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4541 *NeedRetry = TRUE;
4542 return EFI_DEVICE_ERROR;
4543 } else if (Status == EFI_DEVICE_ERROR) {
4544 *NeedRetry = FALSE;
4545 return EFI_DEVICE_ERROR;
4546 }
4547
4548 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4549 DEBUG ((DEBUG_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
4550 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4551 if (Action == ACTION_RETRY_COMMAND_LATER) {
4552 *NeedRetry = TRUE;
4553 return EFI_DEVICE_ERROR;
4554 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4555 if (SectorCount <= 1) {
4556 //
4557 // Jump out if the operation still fails with one sector transfer length.
4558 //
4559 *NeedRetry = FALSE;
4560 return EFI_DEVICE_ERROR;
4561 }
4562
4563 //
4564 // Try again with half length if the sense data shows we need to retry.
4565 //
4566 SectorCount >>= 1;
4567 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4568 goto BackOff;
4569 } else {
4570 *NeedRetry = FALSE;
4571 return EFI_DEVICE_ERROR;
4572 }
4573 }
4574
4575 return ReturnStatus;
4576}
4577
4594 IN SCSI_DISK_DEV *ScsiDiskDevice,
4595 OUT BOOLEAN *NeedRetry,
4596 IN UINT64 Timeout,
4597 IN UINT8 *DataBuffer,
4598 IN OUT UINT32 *DataLength,
4599 IN UINT64 StartLba,
4600 IN UINT32 SectorCount
4601 )
4602{
4603 EFI_STATUS Status;
4604 EFI_STATUS ReturnStatus;
4605 UINT8 SenseDataLength;
4606 UINT8 HostAdapterStatus;
4607 UINT8 TargetStatus;
4608 UINTN Action;
4609
4610 //
4611 // Implement a backoff algorithm to resolve some compatibility issues that
4612 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4613 // big data in a single operation.
4614 // This algorithm will at first try to execute original request. If the request fails
4615 // with media error sense data or else, it will reduce the transfer length to half and
4616 // try again till the operation succeeds or fails with one sector transfer length.
4617 //
4618BackOff:
4619 *NeedRetry = FALSE;
4620 Action = ACTION_NO_ACTION;
4621 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4622 ReturnStatus = ScsiWrite16Command (
4623 ScsiDiskDevice->ScsiIo,
4624 Timeout,
4625 ScsiDiskDevice->SenseData,
4626 &SenseDataLength,
4627 &HostAdapterStatus,
4628 &TargetStatus,
4629 DataBuffer,
4630 DataLength,
4631 StartLba,
4632 SectorCount
4633 );
4634 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4635 *NeedRetry = TRUE;
4636 return EFI_DEVICE_ERROR;
4637 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4638 *NeedRetry = FALSE;
4639 return ReturnStatus;
4640 }
4641
4642 //
4643 // go ahead to check HostAdapterStatus and TargetStatus
4644 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4645 //
4646 Status = CheckHostAdapterStatus (HostAdapterStatus);
4647 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4648 *NeedRetry = TRUE;
4649 return EFI_DEVICE_ERROR;
4650 } else if (Status == EFI_DEVICE_ERROR) {
4651 //
4652 // reset the scsi channel
4653 //
4654 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4655 *NeedRetry = FALSE;
4656 return EFI_DEVICE_ERROR;
4657 }
4658
4659 Status = CheckTargetStatus (TargetStatus);
4660 if (Status == EFI_NOT_READY) {
4661 //
4662 // reset the scsi device
4663 //
4664 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4665 *NeedRetry = TRUE;
4666 return EFI_DEVICE_ERROR;
4667 } else if (Status == EFI_DEVICE_ERROR) {
4668 *NeedRetry = FALSE;
4669 return EFI_DEVICE_ERROR;
4670 }
4671
4672 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4673 DEBUG ((DEBUG_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
4674 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4675 if (Action == ACTION_RETRY_COMMAND_LATER) {
4676 *NeedRetry = TRUE;
4677 return EFI_DEVICE_ERROR;
4678 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4679 if (SectorCount <= 1) {
4680 //
4681 // Jump out if the operation still fails with one sector transfer length.
4682 //
4683 *NeedRetry = FALSE;
4684 return EFI_DEVICE_ERROR;
4685 }
4686
4687 //
4688 // Try again with half length if the sense data shows we need to retry.
4689 //
4690 SectorCount >>= 1;
4691 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4692 goto BackOff;
4693 } else {
4694 *NeedRetry = FALSE;
4695 return EFI_DEVICE_ERROR;
4696 }
4697 }
4698
4699 return ReturnStatus;
4700}
4701
4711VOID
4712EFIAPI
4714 IN EFI_EVENT Event,
4715 IN VOID *Context
4716 )
4717{
4718 EFI_STATUS Status;
4719 SCSI_ASYNC_RW_REQUEST *Request;
4720 SCSI_DISK_DEV *ScsiDiskDevice;
4721 EFI_BLOCK_IO2_TOKEN *Token;
4722 UINTN Action;
4723 UINT32 OldDataLength;
4724 UINT32 OldSectorCount;
4725 UINT8 MaxRetry;
4726
4727 gBS->CloseEvent (Event);
4728
4729 Request = (SCSI_ASYNC_RW_REQUEST *)Context;
4730 ScsiDiskDevice = Request->ScsiDiskDevice;
4731 Token = Request->BlkIo2Req->Token;
4732 OldDataLength = Request->DataLength;
4733 OldSectorCount = Request->SectorCount;
4734 MaxRetry = 2;
4735
4736 //
4737 // If previous sub-tasks already fails, no need to process this sub-task.
4738 //
4739 if (Token->TransactionStatus != EFI_SUCCESS) {
4740 goto Exit;
4741 }
4742
4743 //
4744 // Check HostAdapterStatus and TargetStatus
4745 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4746 //
4747 Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
4748 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4749 if (++Request->TimesRetry > MaxRetry) {
4750 Token->TransactionStatus = EFI_DEVICE_ERROR;
4751 goto Exit;
4752 } else {
4753 goto Retry;
4754 }
4755 } else if (Status == EFI_DEVICE_ERROR) {
4756 //
4757 // reset the scsi channel
4758 //
4759 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4760 Token->TransactionStatus = EFI_DEVICE_ERROR;
4761 goto Exit;
4762 }
4763
4764 Status = CheckTargetStatus (Request->TargetStatus);
4765 if (Status == EFI_NOT_READY) {
4766 //
4767 // reset the scsi device
4768 //
4769 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4770 if (++Request->TimesRetry > MaxRetry) {
4771 Token->TransactionStatus = EFI_DEVICE_ERROR;
4772 goto Exit;
4773 } else {
4774 goto Retry;
4775 }
4776 } else if (Status == EFI_DEVICE_ERROR) {
4777 Token->TransactionStatus = EFI_DEVICE_ERROR;
4778 goto Exit;
4779 }
4780
4781 if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
4782 DEBUG ((DEBUG_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
4783
4785 ScsiDiskDevice,
4786 Request->SenseData,
4787 Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
4788 &Action
4789 );
4790 if (Action == ACTION_RETRY_COMMAND_LATER) {
4791 if (++Request->TimesRetry > MaxRetry) {
4792 Token->TransactionStatus = EFI_DEVICE_ERROR;
4793 goto Exit;
4794 } else {
4795 goto Retry;
4796 }
4797 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4798 if (Request->SectorCount <= 1) {
4799 //
4800 // Jump out if the operation still fails with one sector transfer
4801 // length.
4802 //
4803 Token->TransactionStatus = EFI_DEVICE_ERROR;
4804 goto Exit;
4805 }
4806
4807 //
4808 // Try again with two half length request if the sense data shows we need
4809 // to retry.
4810 //
4811 Request->SectorCount >>= 1;
4812 Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4813 Request->TimesRetry = 0;
4814
4815 goto Retry;
4816 } else {
4817 Token->TransactionStatus = EFI_DEVICE_ERROR;
4818 goto Exit;
4819 }
4820 }
4821
4822 //
4823 // This sub-task succeeds, no need to retry.
4824 //
4825 goto Exit;
4826
4827Retry:
4828 if (Request->InBuffer != NULL) {
4829 //
4830 // SCSI read command
4831 //
4832 if (!ScsiDiskDevice->Cdb16Byte) {
4833 Status = ScsiDiskAsyncRead10 (
4834 ScsiDiskDevice,
4835 Request->Timeout,
4836 Request->TimesRetry,
4837 Request->InBuffer,
4838 Request->DataLength,
4839 (UINT32)Request->StartLba,
4840 Request->SectorCount,
4841 Request->BlkIo2Req,
4842 Token
4843 );
4844 } else {
4845 Status = ScsiDiskAsyncRead16 (
4846 ScsiDiskDevice,
4847 Request->Timeout,
4848 Request->TimesRetry,
4849 Request->InBuffer,
4850 Request->DataLength,
4851 Request->StartLba,
4852 Request->SectorCount,
4853 Request->BlkIo2Req,
4854 Token
4855 );
4856 }
4857
4858 if (EFI_ERROR (Status)) {
4859 Token->TransactionStatus = EFI_DEVICE_ERROR;
4860 goto Exit;
4861 } else if (OldSectorCount != Request->SectorCount) {
4862 //
4863 // Original sub-task will be split into two new sub-tasks with smaller
4864 // DataLength
4865 //
4866 if (!ScsiDiskDevice->Cdb16Byte) {
4867 Status = ScsiDiskAsyncRead10 (
4868 ScsiDiskDevice,
4869 Request->Timeout,
4870 0,
4871 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4872 OldDataLength - Request->DataLength,
4873 (UINT32)Request->StartLba + Request->SectorCount,
4874 OldSectorCount - Request->SectorCount,
4875 Request->BlkIo2Req,
4876 Token
4877 );
4878 } else {
4879 Status = ScsiDiskAsyncRead16 (
4880 ScsiDiskDevice,
4881 Request->Timeout,
4882 0,
4883 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4884 OldDataLength - Request->DataLength,
4885 Request->StartLba + Request->SectorCount,
4886 OldSectorCount - Request->SectorCount,
4887 Request->BlkIo2Req,
4888 Token
4889 );
4890 }
4891
4892 if (EFI_ERROR (Status)) {
4893 Token->TransactionStatus = EFI_DEVICE_ERROR;
4894 goto Exit;
4895 }
4896 }
4897 } else {
4898 //
4899 // SCSI write command
4900 //
4901 if (!ScsiDiskDevice->Cdb16Byte) {
4902 Status = ScsiDiskAsyncWrite10 (
4903 ScsiDiskDevice,
4904 Request->Timeout,
4905 Request->TimesRetry,
4906 Request->OutBuffer,
4907 Request->DataLength,
4908 (UINT32)Request->StartLba,
4909 Request->SectorCount,
4910 Request->BlkIo2Req,
4911 Token
4912 );
4913 } else {
4914 Status = ScsiDiskAsyncWrite16 (
4915 ScsiDiskDevice,
4916 Request->Timeout,
4917 Request->TimesRetry,
4918 Request->OutBuffer,
4919 Request->DataLength,
4920 Request->StartLba,
4921 Request->SectorCount,
4922 Request->BlkIo2Req,
4923 Token
4924 );
4925 }
4926
4927 if (EFI_ERROR (Status)) {
4928 Token->TransactionStatus = EFI_DEVICE_ERROR;
4929 goto Exit;
4930 } else if (OldSectorCount != Request->SectorCount) {
4931 //
4932 // Original sub-task will be split into two new sub-tasks with smaller
4933 // DataLength
4934 //
4935 if (!ScsiDiskDevice->Cdb16Byte) {
4936 Status = ScsiDiskAsyncWrite10 (
4937 ScsiDiskDevice,
4938 Request->Timeout,
4939 0,
4940 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4941 OldDataLength - Request->DataLength,
4942 (UINT32)Request->StartLba + Request->SectorCount,
4943 OldSectorCount - Request->SectorCount,
4944 Request->BlkIo2Req,
4945 Token
4946 );
4947 } else {
4948 Status = ScsiDiskAsyncWrite16 (
4949 ScsiDiskDevice,
4950 Request->Timeout,
4951 0,
4952 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4953 OldDataLength - Request->DataLength,
4954 Request->StartLba + Request->SectorCount,
4955 OldSectorCount - Request->SectorCount,
4956 Request->BlkIo2Req,
4957 Token
4958 );
4959 }
4960
4961 if (EFI_ERROR (Status)) {
4962 Token->TransactionStatus = EFI_DEVICE_ERROR;
4963 goto Exit;
4964 }
4965 }
4966 }
4967
4968Exit:
4969 RemoveEntryList (&Request->Link);
4970 if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
4971 (Request->BlkIo2Req->LastScsiRW))
4972 {
4973 //
4974 // The last SCSI R/W command of a BlockIo2 request completes
4975 //
4976 RemoveEntryList (&Request->BlkIo2Req->Link);
4977 FreePool (Request->BlkIo2Req); // Should be freed only once
4978 gBS->SignalEvent (Token->Event);
4979 }
4980
4981 FreePool (Request->SenseData);
4982 FreePool (Request);
4983}
4984
5007 IN SCSI_DISK_DEV *ScsiDiskDevice,
5008 IN UINT64 Timeout,
5009 IN UINT8 TimesRetry,
5010 OUT UINT8 *DataBuffer,
5011 IN UINT32 DataLength,
5012 IN UINT32 StartLba,
5013 IN UINT32 SectorCount,
5014 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5015 IN EFI_BLOCK_IO2_TOKEN *Token
5016 )
5017{
5018 EFI_STATUS Status;
5019 SCSI_ASYNC_RW_REQUEST *Request;
5020 EFI_EVENT AsyncIoEvent;
5021 EFI_TPL OldTpl;
5022
5023 AsyncIoEvent = NULL;
5024
5025 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5026 if (Request == NULL) {
5027 return EFI_OUT_OF_RESOURCES;
5028 }
5029
5030 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5031 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5032 gBS->RestoreTPL (OldTpl);
5033
5034 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5035 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5036 if (Request->SenseData == NULL) {
5037 Status = EFI_OUT_OF_RESOURCES;
5038 goto ErrorExit;
5039 }
5040
5041 Request->ScsiDiskDevice = ScsiDiskDevice;
5042 Request->Timeout = Timeout;
5043 Request->TimesRetry = TimesRetry;
5044 Request->InBuffer = DataBuffer;
5045 Request->DataLength = DataLength;
5046 Request->StartLba = StartLba;
5047 Request->SectorCount = SectorCount;
5048 Request->BlkIo2Req = BlkIo2Req;
5049
5050 //
5051 // Create Event
5052 //
5053 Status = gBS->CreateEvent (
5054 EVT_NOTIFY_SIGNAL,
5055 TPL_NOTIFY,
5057 Request,
5058 &AsyncIoEvent
5059 );
5060 if (EFI_ERROR (Status)) {
5061 goto ErrorExit;
5062 }
5063
5064 Status = ScsiRead10CommandEx (
5065 ScsiDiskDevice->ScsiIo,
5066 Request->Timeout,
5067 Request->SenseData,
5068 &Request->SenseDataLength,
5069 &Request->HostAdapterStatus,
5070 &Request->TargetStatus,
5071 Request->InBuffer,
5072 &Request->DataLength,
5073 (UINT32)Request->StartLba,
5074 Request->SectorCount,
5075 AsyncIoEvent
5076 );
5077 if (EFI_ERROR (Status)) {
5078 goto ErrorExit;
5079 }
5080
5081 return EFI_SUCCESS;
5082
5083ErrorExit:
5084 if (AsyncIoEvent != NULL) {
5085 gBS->CloseEvent (AsyncIoEvent);
5086 }
5087
5088 if (Request != NULL) {
5089 if (Request->SenseData != NULL) {
5090 FreePool (Request->SenseData);
5091 }
5092
5093 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5094 RemoveEntryList (&Request->Link);
5095 gBS->RestoreTPL (OldTpl);
5096
5097 FreePool (Request);
5098 }
5099
5100 return Status;
5101}
5102
5125 IN SCSI_DISK_DEV *ScsiDiskDevice,
5126 IN UINT64 Timeout,
5127 IN UINT8 TimesRetry,
5128 IN UINT8 *DataBuffer,
5129 IN UINT32 DataLength,
5130 IN UINT32 StartLba,
5131 IN UINT32 SectorCount,
5132 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5133 IN EFI_BLOCK_IO2_TOKEN *Token
5134 )
5135{
5136 EFI_STATUS Status;
5137 SCSI_ASYNC_RW_REQUEST *Request;
5138 EFI_EVENT AsyncIoEvent;
5139 EFI_TPL OldTpl;
5140
5141 AsyncIoEvent = NULL;
5142
5143 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5144 if (Request == NULL) {
5145 return EFI_OUT_OF_RESOURCES;
5146 }
5147
5148 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5149 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5150 gBS->RestoreTPL (OldTpl);
5151
5152 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5153 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5154 if (Request->SenseData == NULL) {
5155 Status = EFI_OUT_OF_RESOURCES;
5156 goto ErrorExit;
5157 }
5158
5159 Request->ScsiDiskDevice = ScsiDiskDevice;
5160 Request->Timeout = Timeout;
5161 Request->TimesRetry = TimesRetry;
5162 Request->OutBuffer = DataBuffer;
5163 Request->DataLength = DataLength;
5164 Request->StartLba = StartLba;
5165 Request->SectorCount = SectorCount;
5166 Request->BlkIo2Req = BlkIo2Req;
5167
5168 //
5169 // Create Event
5170 //
5171 Status = gBS->CreateEvent (
5172 EVT_NOTIFY_SIGNAL,
5173 TPL_NOTIFY,
5175 Request,
5176 &AsyncIoEvent
5177 );
5178 if (EFI_ERROR (Status)) {
5179 goto ErrorExit;
5180 }
5181
5182 Status = ScsiWrite10CommandEx (
5183 ScsiDiskDevice->ScsiIo,
5184 Request->Timeout,
5185 Request->SenseData,
5186 &Request->SenseDataLength,
5187 &Request->HostAdapterStatus,
5188 &Request->TargetStatus,
5189 Request->OutBuffer,
5190 &Request->DataLength,
5191 (UINT32)Request->StartLba,
5192 Request->SectorCount,
5193 AsyncIoEvent
5194 );
5195 if (EFI_ERROR (Status)) {
5196 goto ErrorExit;
5197 }
5198
5199 return EFI_SUCCESS;
5200
5201ErrorExit:
5202 if (AsyncIoEvent != NULL) {
5203 gBS->CloseEvent (AsyncIoEvent);
5204 }
5205
5206 if (Request != NULL) {
5207 if (Request->SenseData != NULL) {
5208 FreePool (Request->SenseData);
5209 }
5210
5211 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5212 RemoveEntryList (&Request->Link);
5213 gBS->RestoreTPL (OldTpl);
5214
5215 FreePool (Request);
5216 }
5217
5218 return Status;
5219}
5220
5243 IN SCSI_DISK_DEV *ScsiDiskDevice,
5244 IN UINT64 Timeout,
5245 IN UINT8 TimesRetry,
5246 OUT UINT8 *DataBuffer,
5247 IN UINT32 DataLength,
5248 IN UINT64 StartLba,
5249 IN UINT32 SectorCount,
5250 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5251 IN EFI_BLOCK_IO2_TOKEN *Token
5252 )
5253{
5254 EFI_STATUS Status;
5255 SCSI_ASYNC_RW_REQUEST *Request;
5256 EFI_EVENT AsyncIoEvent;
5257 EFI_TPL OldTpl;
5258
5259 AsyncIoEvent = NULL;
5260
5261 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5262 if (Request == NULL) {
5263 return EFI_OUT_OF_RESOURCES;
5264 }
5265
5266 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5267 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5268 gBS->RestoreTPL (OldTpl);
5269
5270 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5271 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5272 if (Request->SenseData == NULL) {
5273 Status = EFI_OUT_OF_RESOURCES;
5274 goto ErrorExit;
5275 }
5276
5277 Request->ScsiDiskDevice = ScsiDiskDevice;
5278 Request->Timeout = Timeout;
5279 Request->TimesRetry = TimesRetry;
5280 Request->InBuffer = DataBuffer;
5281 Request->DataLength = DataLength;
5282 Request->StartLba = StartLba;
5283 Request->SectorCount = SectorCount;
5284 Request->BlkIo2Req = BlkIo2Req;
5285
5286 //
5287 // Create Event
5288 //
5289 Status = gBS->CreateEvent (
5290 EVT_NOTIFY_SIGNAL,
5291 TPL_NOTIFY,
5293 Request,
5294 &AsyncIoEvent
5295 );
5296 if (EFI_ERROR (Status)) {
5297 goto ErrorExit;
5298 }
5299
5300 Status = ScsiRead16CommandEx (
5301 ScsiDiskDevice->ScsiIo,
5302 Request->Timeout,
5303 Request->SenseData,
5304 &Request->SenseDataLength,
5305 &Request->HostAdapterStatus,
5306 &Request->TargetStatus,
5307 Request->InBuffer,
5308 &Request->DataLength,
5309 Request->StartLba,
5310 Request->SectorCount,
5311 AsyncIoEvent
5312 );
5313 if (EFI_ERROR (Status)) {
5314 goto ErrorExit;
5315 }
5316
5317 return EFI_SUCCESS;
5318
5319ErrorExit:
5320 if (AsyncIoEvent != NULL) {
5321 gBS->CloseEvent (AsyncIoEvent);
5322 }
5323
5324 if (Request != NULL) {
5325 if (Request->SenseData != NULL) {
5326 FreePool (Request->SenseData);
5327 }
5328
5329 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5330 RemoveEntryList (&Request->Link);
5331 gBS->RestoreTPL (OldTpl);
5332
5333 FreePool (Request);
5334 }
5335
5336 return Status;
5337}
5338
5361 IN SCSI_DISK_DEV *ScsiDiskDevice,
5362 IN UINT64 Timeout,
5363 IN UINT8 TimesRetry,
5364 IN UINT8 *DataBuffer,
5365 IN UINT32 DataLength,
5366 IN UINT64 StartLba,
5367 IN UINT32 SectorCount,
5368 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5369 IN EFI_BLOCK_IO2_TOKEN *Token
5370 )
5371{
5372 EFI_STATUS Status;
5373 SCSI_ASYNC_RW_REQUEST *Request;
5374 EFI_EVENT AsyncIoEvent;
5375 EFI_TPL OldTpl;
5376
5377 AsyncIoEvent = NULL;
5378
5379 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5380 if (Request == NULL) {
5381 return EFI_OUT_OF_RESOURCES;
5382 }
5383
5384 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5385 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5386 gBS->RestoreTPL (OldTpl);
5387
5388 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5389 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5390 if (Request->SenseData == NULL) {
5391 Status = EFI_OUT_OF_RESOURCES;
5392 goto ErrorExit;
5393 }
5394
5395 Request->ScsiDiskDevice = ScsiDiskDevice;
5396 Request->Timeout = Timeout;
5397 Request->TimesRetry = TimesRetry;
5398 Request->OutBuffer = DataBuffer;
5399 Request->DataLength = DataLength;
5400 Request->StartLba = StartLba;
5401 Request->SectorCount = SectorCount;
5402 Request->BlkIo2Req = BlkIo2Req;
5403
5404 //
5405 // Create Event
5406 //
5407 Status = gBS->CreateEvent (
5408 EVT_NOTIFY_SIGNAL,
5409 TPL_NOTIFY,
5411 Request,
5412 &AsyncIoEvent
5413 );
5414 if (EFI_ERROR (Status)) {
5415 goto ErrorExit;
5416 }
5417
5418 Status = ScsiWrite16CommandEx (
5419 ScsiDiskDevice->ScsiIo,
5420 Request->Timeout,
5421 Request->SenseData,
5422 &Request->SenseDataLength,
5423 &Request->HostAdapterStatus,
5424 &Request->TargetStatus,
5425 Request->OutBuffer,
5426 &Request->DataLength,
5427 Request->StartLba,
5428 Request->SectorCount,
5429 AsyncIoEvent
5430 );
5431 if (EFI_ERROR (Status)) {
5432 goto ErrorExit;
5433 }
5434
5435 return EFI_SUCCESS;
5436
5437ErrorExit:
5438 if (AsyncIoEvent != NULL) {
5439 gBS->CloseEvent (AsyncIoEvent);
5440 }
5441
5442 if (Request != NULL) {
5443 if (Request->SenseData != NULL) {
5444 FreePool (Request->SenseData);
5445 }
5446
5447 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5448 RemoveEntryList (&Request->Link);
5449 gBS->RestoreTPL (OldTpl);
5450
5451 FreePool (Request);
5452 }
5453
5454 return Status;
5455}
5456
5466BOOLEAN
5468 IN EFI_SCSI_SENSE_DATA *SenseData,
5469 IN UINTN SenseCounts
5470 )
5471{
5472 EFI_SCSI_SENSE_DATA *SensePtr;
5473 UINTN Index;
5474 BOOLEAN IsNoMedia;
5475
5476 IsNoMedia = FALSE;
5477 SensePtr = SenseData;
5478
5479 for (Index = 0; Index < SenseCounts; Index++) {
5480 //
5481 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
5482 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
5483 //
5484 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
5485 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA))
5486 {
5487 IsNoMedia = TRUE;
5488 }
5489
5490 SensePtr++;
5491 }
5492
5493 return IsNoMedia;
5494}
5495
5506BOOLEAN
5508 IN EFI_SCSI_SENSE_DATA *SenseData,
5509 IN UINTN SenseCounts
5510 )
5511{
5512 EFI_SCSI_SENSE_DATA *SensePtr;
5513 UINTN Index;
5514 BOOLEAN IsError;
5515
5516 IsError = FALSE;
5517 SensePtr = SenseData;
5518
5519 for (Index = 0; Index < SenseCounts; Index++) {
5520 switch (SensePtr->Sense_Key) {
5521 case EFI_SCSI_SK_MEDIUM_ERROR:
5522 //
5523 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
5524 //
5525 switch (SensePtr->Addnl_Sense_Code) {
5526 //
5527 // fall through
5528 //
5529 case EFI_SCSI_ASC_MEDIA_ERR1:
5530
5531 //
5532 // fall through
5533 //
5534 case EFI_SCSI_ASC_MEDIA_ERR2:
5535
5536 //
5537 // fall through
5538 //
5539 case EFI_SCSI_ASC_MEDIA_ERR3:
5540 case EFI_SCSI_ASC_MEDIA_ERR4:
5541 IsError = TRUE;
5542 break;
5543
5544 default:
5545 break;
5546 }
5547
5548 break;
5549
5550 case EFI_SCSI_SK_NOT_READY:
5551 //
5552 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5553 //
5554 switch (SensePtr->Addnl_Sense_Code) {
5555 //
5556 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
5557 //
5558 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
5559 IsError = TRUE;
5560 break;
5561
5562 default:
5563 break;
5564 }
5565
5566 break;
5567
5568 default:
5569 break;
5570 }
5571
5572 SensePtr++;
5573 }
5574
5575 return IsError;
5576}
5577
5588BOOLEAN
5590 IN EFI_SCSI_SENSE_DATA *SenseData,
5591 IN UINTN SenseCounts
5592 )
5593{
5594 EFI_SCSI_SENSE_DATA *SensePtr;
5595 UINTN Index;
5596 BOOLEAN IsError;
5597
5598 IsError = FALSE;
5599 SensePtr = SenseData;
5600
5601 for (Index = 0; Index < SenseCounts; Index++) {
5602 //
5603 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
5604 //
5605 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
5606 IsError = TRUE;
5607 }
5608
5609 SensePtr++;
5610 }
5611
5612 return IsError;
5613}
5614
5624BOOLEAN
5626 IN EFI_SCSI_SENSE_DATA *SenseData,
5627 IN UINTN SenseCounts
5628 )
5629{
5630 EFI_SCSI_SENSE_DATA *SensePtr;
5631 UINTN Index;
5632 BOOLEAN IsMediaChanged;
5633
5634 IsMediaChanged = FALSE;
5635 SensePtr = SenseData;
5636
5637 for (Index = 0; Index < SenseCounts; Index++) {
5638 //
5639 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5640 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5641 //
5642 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5643 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE))
5644 {
5645 IsMediaChanged = TRUE;
5646 }
5647
5648 SensePtr++;
5649 }
5650
5651 return IsMediaChanged;
5652}
5653
5664BOOLEAN
5666 IN EFI_SCSI_SENSE_DATA *SenseData,
5667 IN UINTN SenseCounts
5668 )
5669{
5670 EFI_SCSI_SENSE_DATA *SensePtr;
5671 UINTN Index;
5672 BOOLEAN IsResetBefore;
5673
5674 IsResetBefore = FALSE;
5675 SensePtr = SenseData;
5676
5677 for (Index = 0; Index < SenseCounts; Index++) {
5678 //
5679 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5680 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5681 //
5682 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5683 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET))
5684 {
5685 IsResetBefore = TRUE;
5686 }
5687
5688 SensePtr++;
5689 }
5690
5691 return IsResetBefore;
5692}
5693
5705BOOLEAN
5707 IN EFI_SCSI_SENSE_DATA *SenseData,
5708 IN UINTN SenseCounts,
5709 OUT BOOLEAN *RetryLater
5710 )
5711{
5712 EFI_SCSI_SENSE_DATA *SensePtr;
5713 UINTN Index;
5714 BOOLEAN IsReady;
5715
5716 IsReady = TRUE;
5717 *RetryLater = FALSE;
5718 SensePtr = SenseData;
5719
5720 for (Index = 0; Index < SenseCounts; Index++) {
5721 switch (SensePtr->Sense_Key) {
5722 case EFI_SCSI_SK_NOT_READY:
5723 //
5724 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5725 //
5726 switch (SensePtr->Addnl_Sense_Code) {
5727 case EFI_SCSI_ASC_NOT_READY:
5728 //
5729 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5730 //
5731 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
5732 case EFI_SCSI_ASCQ_IN_PROGRESS:
5733 //
5734 // Additional Sense Code Qualifier is
5735 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5736 //
5737 IsReady = FALSE;
5738 *RetryLater = TRUE;
5739 break;
5740
5741 default:
5742 IsReady = FALSE;
5743 *RetryLater = FALSE;
5744 break;
5745 }
5746
5747 break;
5748
5749 default:
5750 break;
5751 }
5752
5753 break;
5754
5755 default:
5756 break;
5757 }
5758
5759 SensePtr++;
5760 }
5761
5762 return IsReady;
5763}
5764
5775BOOLEAN
5777 IN EFI_SCSI_SENSE_DATA *SenseData,
5778 IN UINTN SenseCounts
5779 )
5780{
5781 EFI_SCSI_SENSE_DATA *SensePtr;
5782 UINTN Index;
5783 BOOLEAN HaveSenseKey;
5784
5785 if (SenseCounts == 0) {
5786 HaveSenseKey = FALSE;
5787 } else {
5788 HaveSenseKey = TRUE;
5789 }
5790
5791 SensePtr = SenseData;
5792
5793 for (Index = 0; Index < SenseCounts; Index++) {
5794 //
5795 // Sense Key is SK_NO_SENSE (0x0)
5796 //
5797 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
5798 (Index == 0))
5799 {
5800 HaveSenseKey = FALSE;
5801 }
5802
5803 SensePtr++;
5804 }
5805
5806 return HaveSenseKey;
5807}
5808
5815VOID
5817 IN SCSI_DISK_DEV *ScsiDiskDevice
5818 )
5819{
5820 if (ScsiDiskDevice == NULL) {
5821 return;
5822 }
5823
5824 if (ScsiDiskDevice->SenseData != NULL) {
5825 FreePool (ScsiDiskDevice->SenseData);
5826 ScsiDiskDevice->SenseData = NULL;
5827 }
5828
5829 if (ScsiDiskDevice->ControllerNameTable != NULL) {
5830 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
5831 ScsiDiskDevice->ControllerNameTable = NULL;
5832 }
5833
5834 FreePool (ScsiDiskDevice);
5835
5836 ScsiDiskDevice = NULL;
5837}
5838
5849BOOLEAN
5851 IN EFI_HANDLE ChildHandle
5852 )
5853{
5854 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
5855 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
5856
5857 //
5858 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5859 // check its attribute, logic or physical.
5860 //
5861 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
5862 if (ExtScsiPassThru != NULL) {
5863 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5864 return TRUE;
5865 }
5866 }
5867
5868 //
5869 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5870 // check its attribute, logic or physical.
5871 //
5872 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
5873 if (ScsiPassThru != NULL) {
5874 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5875 return TRUE;
5876 }
5877 }
5878
5879 return FALSE;
5880}
5881
5894VOID *
5895EFIAPI
5897 IN EFI_GUID *ProtocolGuid,
5898 IN EFI_HANDLE ChildHandle
5899 )
5900{
5901 UINTN Index;
5902 UINTN HandleCount;
5903 VOID *Interface;
5904 EFI_STATUS Status;
5905 EFI_HANDLE *HandleBuffer;
5906
5907 //
5908 // Retrieve the list of all handles from the handle database
5909 //
5910 Status = gBS->LocateHandleBuffer (
5911 ByProtocol,
5912 ProtocolGuid,
5913 NULL,
5914 &HandleCount,
5915 &HandleBuffer
5916 );
5917
5918 if (EFI_ERROR (Status)) {
5919 return NULL;
5920 }
5921
5922 //
5923 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5924 //
5925 for (Index = 0; Index < HandleCount; Index++) {
5926 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
5927 if (!EFI_ERROR (Status)) {
5928 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
5929 if (!EFI_ERROR (Status)) {
5930 gBS->FreePool (HandleBuffer);
5931 return Interface;
5932 }
5933 }
5934 }
5935
5936 gBS->FreePool (HandleBuffer);
5937 return NULL;
5938}
5939
5950BOOLEAN
5952 IN SCSI_DISK_DEV *ScsiDiskDevice,
5953 IN EFI_HANDLE ChildHandle
5954 )
5955{
5956 UINT8 HostAdapterStatus;
5957 UINT8 TargetStatus;
5958 EFI_STATUS CommandStatus;
5959 EFI_STATUS Status;
5960 BOOLEAN UfsDevice;
5961 BOOLEAN RetVal;
5962 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
5963 UINT8 SenseDataLength;
5964 UINT32 DataLength16;
5965 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
5966
5967 UfsDevice = FALSE;
5968 RetVal = TRUE;
5969 CapacityData16 = NULL;
5970
5971 //
5972 // UNMAP command is not supported by any of the UFS WLUNs.
5973 //
5974 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
5975 RetVal = FALSE;
5976 goto Done;
5977 }
5978
5979 Status = gBS->HandleProtocol (
5980 ChildHandle,
5981 &gEfiDevicePathProtocolGuid,
5982 (VOID **)&DevicePathNode
5983 );
5984 //
5985 // Device Path protocol must be installed on the device handle.
5986 //
5987 ASSERT_EFI_ERROR (Status);
5988
5989 while (!IsDevicePathEndType (DevicePathNode)) {
5990 //
5991 // For now, only support Erase Block Protocol on UFS devices.
5992 //
5993 if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
5994 (DevicePathNode->SubType == MSG_UFS_DP))
5995 {
5996 UfsDevice = TRUE;
5997 break;
5998 }
5999
6000 DevicePathNode = NextDevicePathNode (DevicePathNode);
6001 }
6002
6003 if (!UfsDevice) {
6004 RetVal = FALSE;
6005 goto Done;
6006 }
6007
6008 //
6009 // Check whether the erase functionality is enabled on the UFS device.
6010 //
6011 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
6012 if (CapacityData16 == NULL) {
6013 RetVal = FALSE;
6014 goto Done;
6015 }
6016
6017 SenseDataLength = 0;
6018 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
6019 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
6020
6021 CommandStatus = ScsiReadCapacity16Command (
6022 ScsiDiskDevice->ScsiIo,
6023 SCSI_DISK_TIMEOUT,
6024 NULL,
6025 &SenseDataLength,
6026 &HostAdapterStatus,
6027 &TargetStatus,
6028 (VOID *)CapacityData16,
6029 &DataLength16,
6030 FALSE
6031 );
6032
6033 if (CommandStatus == EFI_SUCCESS) {
6034 //
6035 // Universal Flash Storage (UFS) Version 2.0
6036 // Section 11.3.9.2
6037 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
6038 //
6039 if (((CapacityData16->LowestAlignLogic2 & BIT7) == 0) ||
6040 ((CapacityData16->LowestAlignLogic2 & BIT6) == 0))
6041 {
6042 DEBUG ((
6043 DEBUG_VERBOSE,
6044 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
6045 CapacityData16->LowestAlignLogic2
6046 ));
6047
6048 RetVal = FALSE;
6049 goto Done;
6050 }
6051 } else {
6052 DEBUG ((
6053 DEBUG_VERBOSE,
6054 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
6055 CommandStatus
6056 ));
6057
6058 RetVal = FALSE;
6059 goto Done;
6060 }
6061
6062 //
6063 // Check whether the UFS device server implements the UNMAP command.
6064 //
6065 if ((ScsiDiskDevice->UnmapInfo.MaxLbaCnt == 0) ||
6066 (ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt == 0))
6067 {
6068 DEBUG ((
6069 DEBUG_VERBOSE,
6070 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
6071 ));
6072
6073 RetVal = FALSE;
6074 goto Done;
6075 }
6076
6077Done:
6078 if (CapacityData16 != NULL) {
6079 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
6080 }
6081
6082 return RetVal;
6083}
6084
6095BOOLEAN
6097 IN SCSI_DISK_DEV *ScsiDiskDevice,
6098 IN EFI_HANDLE ChildHandle
6099 )
6100{
6101 EFI_STATUS Status;
6103 BOOLEAN RetVal;
6104 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
6105
6106 UfsDevice = NULL;
6107 RetVal = TRUE;
6108
6109 Status = gBS->HandleProtocol (
6110 ChildHandle,
6111 &gEfiDevicePathProtocolGuid,
6112 (VOID **)&DevicePathNode
6113 );
6114 //
6115 // Device Path protocol must be installed on the device handle.
6116 //
6117 ASSERT_EFI_ERROR (Status);
6118
6119 while (!IsDevicePathEndType (DevicePathNode)) {
6120 //
6121 // For now, only support Storage Security Command Protocol on UFS devices.
6122 //
6123 if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
6124 (DevicePathNode->SubType == MSG_UFS_DP))
6125 {
6126 UfsDevice = (UFS_DEVICE_PATH *)DevicePathNode;
6127 break;
6128 }
6129
6130 DevicePathNode = NextDevicePathNode (DevicePathNode);
6131 }
6132
6133 if (UfsDevice == NULL) {
6134 RetVal = FALSE;
6135 goto Done;
6136 }
6137
6138 if (UfsDevice->Lun != UFS_WLUN_RPMB) {
6139 RetVal = FALSE;
6140 }
6141
6142Done:
6143 return RetVal;
6144}
6145
6163EFIAPI
6166 IN OUT VOID *InquiryData,
6167 IN OUT UINT32 *InquiryDataSize
6168 )
6169{
6170 EFI_STATUS Status;
6171 SCSI_DISK_DEV *ScsiDiskDevice;
6172
6173 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
6174
6175 Status = EFI_BUFFER_TOO_SMALL;
6176 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
6177 Status = EFI_SUCCESS;
6178 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
6179 }
6180
6181 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
6182 return Status;
6183}
6184
6204EFIAPI
6207 IN OUT VOID *IdentifyData,
6208 IN OUT UINT32 *IdentifyDataSize
6209 )
6210{
6211 EFI_STATUS Status;
6212 SCSI_DISK_DEV *ScsiDiskDevice;
6213
6214 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
6215 //
6216 // Physical SCSI bus does not support this data class.
6217 //
6218 return EFI_NOT_FOUND;
6219 }
6220
6221 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
6222
6223 Status = EFI_BUFFER_TOO_SMALL;
6224 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
6225 Status = EFI_SUCCESS;
6226 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
6227 }
6228
6229 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
6230 return Status;
6231}
6232
6251EFIAPI
6254 IN OUT VOID *SenseData,
6255 IN OUT UINT32 *SenseDataSize,
6256 OUT UINT8 *SenseDataNumber
6257 )
6258{
6259 return EFI_NOT_FOUND;
6260}
6261
6274EFIAPI
6277 OUT UINT32 *IdeChannel,
6278 OUT UINT32 *IdeDevice
6279 )
6280{
6281 SCSI_DISK_DEV *ScsiDiskDevice;
6282
6283 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
6284 //
6285 // This is not an IDE physical device.
6286 //
6287 return EFI_UNSUPPORTED;
6288 }
6289
6290 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
6291 *IdeChannel = ScsiDiskDevice->Channel;
6292 *IdeDevice = ScsiDiskDevice->Device;
6293
6294 return EFI_SUCCESS;
6295}
6296
6312 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
6313 )
6314{
6315 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
6316 UINT8 Cdb[6];
6317
6318 //
6319 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
6320 //
6321 ZeroMem (&CommandPacket, sizeof (CommandPacket));
6322 ZeroMem (Cdb, sizeof (Cdb));
6323
6324 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
6325 CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
6326 CommandPacket.Cdb = Cdb;
6327 CommandPacket.CdbLength = (UINT8)sizeof (Cdb);
6328 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
6329 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
6330
6331 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
6332}
6333
6346VOID
6348 IN SCSI_DISK_DEV *ScsiDiskDevice,
6349 IN EFI_HANDLE ChildHandle
6350 )
6351{
6352 EFI_STATUS Status;
6353 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
6354 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
6355 ATAPI_DEVICE_PATH *AtapiDevicePath;
6356 SATA_DEVICE_PATH *SataDevicePath;
6357 UINTN IdentifyRetry;
6358
6359 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathNode);
6360 //
6361 // Device Path protocol must be installed on the device handle.
6362 //
6363 ASSERT_EFI_ERROR (Status);
6364 //
6365 // Copy the DiskInfo protocol template.
6366 //
6367 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
6368
6369 while (!IsDevicePathEnd (DevicePathNode)) {
6370 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
6371 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
6372 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
6373 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
6374 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
6375 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP)))
6376 {
6377 IdentifyRetry = 3;
6378 do {
6379 //
6380 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
6381 // with IDE/AHCI interface GUID.
6382 //
6383 Status = AtapiIdentifyDevice (ScsiDiskDevice);
6384 if (!EFI_ERROR (Status)) {
6385 if (DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) {
6386 //
6387 // We find the valid ATAPI device path
6388 //
6389 AtapiDevicePath = (ATAPI_DEVICE_PATH *)ChildDevicePathNode;
6390 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
6391 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
6392 //
6393 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
6394 //
6395 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
6396 } else {
6397 //
6398 // We find the valid SATA device path
6399 //
6400 SataDevicePath = (SATA_DEVICE_PATH *)ChildDevicePathNode;
6401 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
6402 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
6403 //
6404 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
6405 //
6406 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
6407 }
6408
6409 return;
6410 }
6411 } while (--IdentifyRetry > 0);
6412 } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
6413 (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP))
6414 {
6415 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
6416 break;
6417 }
6418
6419 DevicePathNode = ChildDevicePathNode;
6420 }
6421
6422 return;
6423}
UINT64 UINTN
#define ATA_CMD_IDENTIFY_DEVICE
defined from ATA-3
Definition: Atapi.h:488
BOOLEAN IsNoMedia(IN ATAPI_REQUEST_SENSE_DATA *SenseData, IN UINTN SenseCounts)
Definition: AtapiPeim.c:2280
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
UINT16 EFIAPI SwapBytes16(IN UINT16 Value)
Definition: SwapBytes16.c:25
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
UINT32 EFIAPI SwapBytes32(IN UINT32 Value)
Definition: SwapBytes32.c:25
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
UINT16 EFIAPI WriteUnaligned16(OUT UINT16 *Buffer, IN UINT16 Value)
Definition: Unaligned.c:61
UINT64 EFIAPI SwapBytes64(IN UINT64 Value)
Definition: SwapBytes64.c:25
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
Definition: MemLibGuid.c:39
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define HARDWARE_DEVICE_PATH
Definition: DevicePath.h:68
#define MSG_ATAPI_DP
Definition: DevicePath.h:326
#define MSG_UFS_DP
Definition: DevicePath.h:891
#define MSG_SATA_DP
Definition: DevicePath.h:510
#define HW_PCI_DP
Definition: DevicePath.h:73
#define MESSAGING_DEVICE_PATH
Definition: DevicePath.h:321
UINT8 EFIAPI DevicePathType(IN CONST VOID *Node)
UINT8 EFIAPI DevicePathSubType(IN CONST VOID *Node)
BOOLEAN EFIAPI IsDevicePathEnd(IN CONST VOID *Node)
EFI_DEVICE_PATH_PROTOCOL *EFIAPI NextDevicePathNode(IN CONST VOID *Node)
BOOLEAN EFIAPI IsDevicePathEndType(IN CONST VOID *Node)
#define EFI_DISK_INFO_SCSI_INTERFACE_GUID
Definition: DiskInfo.h:41
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID EFIAPI FreeAlignedPages(IN VOID *Buffer, IN UINTN Pages)
UINTN EFIAPI UnicodeSPrint(OUT CHAR16 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR16 *FormatString,...)
Definition: PrintLib.c:408
#define NULL
Definition: Base.h:319
#define ADDRESS_IS_ALIGNED(Address, Alignment)
Definition: Base.h:923
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
@ UfsDevice
The recovery device is a Universal Flash Storage device.
Definition: BlockIo.h:53
VOID *EFIAPI AllocateAlignedPages(IN UINTN Pages, IN UINTN Alignment)
#define EFI_SCSI_ASC_RESET
Power On Reset or Bus Reset occurred.
Definition: Scsi.h:420
#define EFI_SCSI_TYPE_DISK
Direct-access device (e.g. magnetic disk)
Definition: Scsi.h:187
#define EFI_SCSI_TYPE_CDROM
CD/DVD device.
Definition: Scsi.h:192
#define EFI_SCSI_TYPE_WLUN
Well known logical unit.
Definition: Scsi.h:209
EFI_STATUS EFIAPI ScsiDiskDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL)
Definition: ScsiDisk.c:458
EFI_STATUS EFIAPI InitializeScsiDisk(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: ScsiDisk.c:112
VOID ParseInquiryData(IN OUT SCSI_DISK_DEV *ScsiDiskDevice)
Definition: ScsiDisk.c:3434
EFI_STATUS 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)
Definition: ScsiDisk.c:1188
EFI_STATUS EFIAPI ScsiDiskSendData(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, IN UINT32 MediaId OPTIONAL, IN UINT64 Timeout, IN UINT8 SecurityProtocolId, IN UINT16 SecurityProtocolSpecificData, IN UINTN PayloadBufferSize, OUT VOID *PayloadBuffer)
Definition: ScsiDisk.c:2154
EFI_STATUS EFIAPI ScsiDiskFlushBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL *This, IN OUT EFI_BLOCK_IO2_TOKEN *Token)
Definition: ScsiDisk.c:1363
VOID * AllocateAlignedBuffer(IN SCSI_DISK_DEV *ScsiDiskDevice, IN UINTN BufferSize)
Definition: ScsiDisk.c:42
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)
Definition: ScsiDisk.c:5124
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)
Definition: ScsiDisk.c:5242
EFI_STATUS EFIAPI ScsiDiskDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
Definition: ScsiDisk.c:156
BOOLEAN ScsiDiskIsHardwareError(IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN SenseCounts)
Definition: ScsiDisk.c:5589
EFI_STATUS ScsiDiskReadSectors(IN SCSI_DISK_DEV *ScsiDiskDevice, OUT VOID *Buffer, IN EFI_LBA Lba, IN UINTN NumberOfBlocks)
Definition: ScsiDisk.c:3455
EFI_STATUS EFIAPI ScsiDiskInfoWhichIde(IN EFI_DISK_INFO_PROTOCOL *This, OUT UINT32 *IdeChannel, OUT UINT32 *IdeDevice)
Definition: ScsiDisk.c:6275
EFI_STATUS ScsiDiskRequestSenseKeys(IN OUT SCSI_DISK_DEV *ScsiDiskDevice, OUT BOOLEAN *NeedRetry, OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OUT UINTN *NumberOfSenseKeys, IN BOOLEAN AskResetIfError)
Definition: ScsiDisk.c:3276
EFI_STATUS EFIAPI ScsiDiskFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL *This)
Definition: ScsiDisk.c:917
BOOLEAN ScsiDiskIsResetBefore(IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN SenseCounts)
Definition: ScsiDisk.c:5665
EFI_STATUS EFIAPI ScsiDiskInfoInquiry(IN EFI_DISK_INFO_PROTOCOL *This, IN OUT VOID *InquiryData, IN OUT UINT32 *InquiryDataSize)
Definition: ScsiDisk.c:6164
VOID FreeAlignedBuffer(IN VOID *Buffer, IN UINTN BufferSize)
Definition: ScsiDisk.c:61
EFI_STATUS EFIAPI ScsiDiskReceiveData(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, IN UINT32 MediaId OPTIONAL, IN UINT64 Timeout, IN UINT8 SecurityProtocolId, IN UINT16 SecurityProtocolSpecificData, IN UINTN PayloadBufferSize, OUT VOID *PayloadBuffer, OUT UINTN *PayloadTransferSize)
Definition: ScsiDisk.c:1936
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)
Definition: ScsiDisk.c:5006
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)
Definition: ScsiDisk.c:4346
EFI_STATUS ScsiDiskUnmap(IN SCSI_DISK_DEV *ScsiDiskDevice, IN UINT64 Lba, IN UINTN Blocks, IN EFI_ERASE_BLOCK_TOKEN *Token OPTIONAL)
Definition: ScsiDisk.c:1532
EFI_STATUS AtapiIdentifyDevice(IN OUT SCSI_DISK_DEV *ScsiDiskDevice)
Definition: ScsiDisk.c:6311
EFI_STATUS ScsiDiskInquiryDevice(IN OUT SCSI_DISK_DEV *ScsiDiskDevice, OUT BOOLEAN *NeedRetry)
Definition: ScsiDisk.c:2526
BOOLEAN ScsiDiskHaveSenseKey(IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN SenseCounts)
Definition: ScsiDisk.c:5776
BOOLEAN ScsiDiskIsMediaChange(IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN SenseCounts)
Definition: ScsiDisk.c:5625
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)
Definition: ScsiDisk.c:4221
EFI_STATUS EFIAPI ScsiDiskReadBlocks(IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, OUT VOID *Buffer)
Definition: ScsiDisk.c:616
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)
Definition: ScsiDisk.c:5360
EFI_STATUS ScsiDiskAsyncWriteSectors(IN SCSI_DISK_DEV *ScsiDiskDevice, IN VOID *Buffer, IN EFI_LBA Lba, IN UINTN NumberOfBlocks, IN EFI_BLOCK_IO2_TOKEN *Token)
Definition: ScsiDisk.c:4005
BOOLEAN DetermineInstallEraseBlock(IN SCSI_DISK_DEV *ScsiDiskDevice, IN EFI_HANDLE ChildHandle)
Definition: ScsiDisk.c:5951
VOID EFIAPI ScsiDiskNotify(IN EFI_EVENT Event, IN VOID *Context)
Definition: ScsiDisk.c:4713
EFI_STATUS EFIAPI ScsiDiskReset(IN EFI_BLOCK_IO_PROTOCOL *This, IN BOOLEAN ExtendedVerification)
Definition: ScsiDisk.c:557
EFI_STATUS EFIAPI ScsiDiskWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer)
Definition: ScsiDisk.c:768
VOID GetMediaInfo(IN OUT SCSI_DISK_DEV *ScsiDiskDevice, IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10, IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16)
Definition: ScsiDisk.c:3373
EFI_STATUS DetectMediaParsingSenseKeys(OUT SCSI_DISK_DEV *ScsiDiskDevice, IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN NumberOfSenseKeys, OUT UINTN *Action)
Definition: ScsiDisk.c:2923
EFI_STATUS EFIAPI ScsiDiskInfoSenseData(IN EFI_DISK_INFO_PROTOCOL *This, IN OUT VOID *SenseData, IN OUT UINT32 *SenseDataSize, OUT UINT8 *SenseDataNumber)
Definition: ScsiDisk.c:6252
VOID ReleaseScsiDiskDeviceResources(IN SCSI_DISK_DEV *ScsiDiskDevice)
Definition: ScsiDisk.c:5816
EFI_STATUS CheckTargetStatus(IN UINT8 TargetStatus)
Definition: ScsiDisk.c:3234
EFI_STATUS ScsiDiskTestUnitReady(IN SCSI_DISK_DEV *ScsiDiskDevice, OUT BOOLEAN *NeedRetry, OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OUT UINTN *NumberOfSenseKeys)
Definition: ScsiDisk.c:2809
EFI_STATUS ScsiDiskWriteSectors(IN SCSI_DISK_DEV *ScsiDiskDevice, IN VOID *Buffer, IN EFI_LBA Lba, IN UINTN NumberOfBlocks)
Definition: ScsiDisk.c:3620
EFI_STATUS EFIAPI ScsiDiskResetEx(IN EFI_BLOCK_IO2_PROTOCOL *This, IN BOOLEAN ExtendedVerification)
Definition: ScsiDisk.c:941
UINTN RemoveTrailingSpaces(IN OUT CHAR8 *String)
Definition: ScsiDisk.c:79
BOOLEAN DetermineInstallStorageSecurity(IN SCSI_DISK_DEV *ScsiDiskDevice, IN EFI_HANDLE ChildHandle)
Definition: ScsiDisk.c:6096
EFI_STATUS ScsiDiskAsyncReadSectors(IN SCSI_DISK_DEV *ScsiDiskDevice, OUT VOID *Buffer, IN EFI_LBA Lba, IN UINTN NumberOfBlocks, IN EFI_BLOCK_IO2_TOKEN *Token)
Definition: ScsiDisk.c:3787
BOOLEAN ScsiDiskIsMediaError(IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN SenseCounts)
Definition: ScsiDisk.c:5507
EFI_STATUS ScsiDiskReadCapacity(IN OUT SCSI_DISK_DEV *ScsiDiskDevice, OUT BOOLEAN *NeedRetry, OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OUT UINTN *NumberOfSenseKeys)
Definition: ScsiDisk.c:3017
BOOLEAN ScsiDiskIsDriveReady(IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN SenseCounts, OUT BOOLEAN *RetryLater)
Definition: ScsiDisk.c:5706
VOID EFIAPI ScsiDiskAsyncUnmapNotify(IN EFI_EVENT Event, IN VOID *Context)
Definition: ScsiDisk.c:1468
BOOLEAN DetermineInstallBlockIo(IN EFI_HANDLE ChildHandle)
Definition: ScsiDisk.c:5850
EFI_STATUS CheckHostAdapterStatus(IN UINT8 HostAdapterStatus)
Definition: ScsiDisk.c:3194
EFI_STATUS ScsiDiskDetectMedia(IN SCSI_DISK_DEV *ScsiDiskDevice, IN BOOLEAN MustReadCapacity, OUT BOOLEAN *MediaChange)
Definition: ScsiDisk.c:2319
EFI_STATUS 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)
Definition: ScsiDisk.c:1009
EFI_STATUS 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)
Definition: ScsiDisk.c:1752
VOID *EFIAPI GetParentProtocol(IN EFI_GUID *ProtocolGuid, IN EFI_HANDLE ChildHandle)
Definition: ScsiDisk.c:5896
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)
Definition: ScsiDisk.c:4469
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)
Definition: ScsiDisk.c:4593
EFI_STATUS EFIAPI ScsiDiskDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
Definition: ScsiDisk.c:220
VOID InitializeInstallDiskInfo(IN SCSI_DISK_DEV *ScsiDiskDevice, IN EFI_HANDLE ChildHandle)
Definition: ScsiDisk.c:6347
EFI_STATUS EFIAPI ScsiDiskInfoIdentify(IN EFI_DISK_INFO_PROTOCOL *This, IN OUT VOID *IdentifyData, IN OUT UINT32 *IdentifyDataSize)
Definition: ScsiDisk.c:6205
BOOLEAN ScsiDiskIsNoMedia(IN EFI_SCSI_SENSE_DATA *SenseData, IN UINTN SenseCounts)
Definition: ScsiDisk.c:5467
VOID EFIAPI Exit(IN EFI_STATUS Status)
UINT64 EFI_LBA
Definition: UefiBaseType.h:45
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI AddUnicodeString2(IN CONST CHAR8 *Language, IN CONST CHAR8 *SupportedLanguages, IN OUT EFI_UNICODE_STRING_TABLE **UnicodeStringTable, IN CONST CHAR16 *UnicodeString, IN BOOLEAN Iso639Language)
Definition: UefiLib.c:1087
#define EFI_TIMER_PERIOD_SECONDS(Seconds)
Definition: UefiLib.h:98
EFI_STATUS EFIAPI EfiTestChildHandle(IN CONST EFI_HANDLE ControllerHandle, IN CONST EFI_HANDLE ChildHandle, IN CONST EFI_GUID *ProtocolGuid)
Definition: UefiLib.c:597
EFI_STATUS EFIAPI EfiLibInstallDriverBindingComponentName2(IN CONST EFI_HANDLE ImageHandle, IN CONST EFI_SYSTEM_TABLE *SystemTable, IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, IN EFI_HANDLE DriverBindingHandle, IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName OPTIONAL, IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL)
EFI_STATUS EFIAPI FreeUnicodeStringTable(IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable)
Definition: UefiLib.c:1257
EFI_STATUS EFIAPI ScsiWrite10CommandEx(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT32 StartLba, IN UINT32 SectorSize, IN EFI_EVENT Event OPTIONAL)
Definition: UefiScsiLib.c:1802
EFI_STATUS EFIAPI ScsiSecurityProtocolInCommand(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN UINT8 SecurityProtocol, IN UINT16 SecurityProtocolSpecific, IN BOOLEAN Inc512, IN UINTN DataLength, IN OUT VOID *DataBuffer OPTIONAL, OUT UINTN *TransferLength)
Definition: UefiScsiLib.c:1323
EFI_STATUS EFIAPI ScsiRead10CommandEx(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT32 StartLba, IN UINT32 SectorSize, IN EFI_EVENT Event OPTIONAL)
Definition: UefiScsiLib.c:1619
EFI_STATUS EFIAPI ScsiRead10Command(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT32 StartLba, IN UINT32 SectorSize)
Definition: UefiScsiLib.c:922
EFI_STATUS EFIAPI ScsiTestUnitReadyCommand(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus)
Definition: UefiScsiLib.c:129
EFI_STATUS EFIAPI ScsiWrite16Command(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT64 StartLba, IN UINT32 SectorSize)
Definition: UefiScsiLib.c:1220
EFI_STATUS EFIAPI ScsiRequestSenseCommand(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus)
Definition: UefiScsiLib.c:622
EFI_STATUS EFIAPI ScsiInquiryCommandEx(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *InquiryDataBuffer OPTIONAL, IN OUT UINT32 *InquiryDataLength, IN BOOLEAN EnableVitalProductData, IN UINT8 PageCode)
Definition: UefiScsiLib.c:264
EFI_STATUS EFIAPI ScsiWrite16CommandEx(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT64 StartLba, IN UINT32 SectorSize, IN EFI_EVENT Event OPTIONAL)
Definition: UefiScsiLib.c:2168
EFI_STATUS EFIAPI ScsiSecurityProtocolOutCommand(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN UINT8 SecurityProtocol, IN UINT16 SecurityProtocolSpecific, IN BOOLEAN Inc512, IN UINTN DataLength, IN OUT VOID *DataBuffer OPTIONAL)
Definition: UefiScsiLib.c:1436
EFI_STATUS EFIAPI ScsiRead16CommandEx(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT64 StartLba, IN UINT32 SectorSize, IN EFI_EVENT Event OPTIONAL)
Definition: UefiScsiLib.c:1985
EFI_STATUS EFIAPI ScsiInquiryCommand(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *InquiryDataBuffer OPTIONAL, IN OUT UINT32 *InquiryDataLength, IN BOOLEAN EnableVitalProductData)
Definition: UefiScsiLib.c:410
EFI_STATUS EFIAPI ScsiReadCapacity16Command(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN BOOLEAN Pmi)
Definition: UefiScsiLib.c:816
EFI_STATUS EFIAPI ScsiRead16Command(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT64 StartLba, IN UINT32 SectorSize)
Definition: UefiScsiLib.c:1121
EFI_STATUS EFIAPI ScsiWrite10Command(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN UINT32 StartLba, IN UINT32 SectorSize)
Definition: UefiScsiLib.c:1021
EFI_STATUS EFIAPI ScsiReadCapacityCommand(IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData OPTIONAL, IN OUT UINT8 *SenseDataLength, OUT UINT8 *HostAdapterStatus, OUT UINT8 *TargetStatus, IN OUT VOID *DataBuffer OPTIONAL, IN OUT UINT32 *DataLength, IN BOOLEAN Pmi)
Definition: UefiScsiLib.c:713
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
@ TimerRelative
Definition: UefiSpec.h:539
@ ByProtocol
Definition: UefiSpec.h:1518
EFI_BLOCK_IO_MEDIA * Media
Definition: BlockIo2.h:187
EFI_BLOCK_IO_MEDIA * Media
Definition: BlockIo.h:224
EFI_EXT_SCSI_PASS_THRU_MODE * Mode
EFI_SCSI_PASS_THRU_MODE * Mode
Definition: ScsiPassThru.h:366
UINT8 PrimarySecondary
Definition: DevicePath.h:332
EFI_EVENT Event
Definition: BlockIo2.h:34
EFI_STATUS TransactionStatus
Definition: BlockIo2.h:39
UINT32 BlockSize
Definition: BlockIo.h:167
EFI_LBA LastBlock
Definition: BlockIo.h:178
BOOLEAN MediaPresent
Definition: BlockIo.h:144
BOOLEAN ReadOnly
Definition: BlockIo.h:156
UINT8 Addnl_Sense_Code
Additional sense code.
Definition: Scsi.h:328
UINT8 Addnl_Sense_Code_Qualifier
Additional sense code qualifier.
Definition: Scsi.h:329
Definition: Base.h:213
UINT16 PortMultiplierPortNumber
Definition: DevicePath.h:523
UINT16 HBAPortNumber
Definition: DevicePath.h:517