]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
MdeModulePkg: ScsiDiskDxe: clean up comment in ScsiDisk.c
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiDiskDxe / ScsiDisk.c
1 /** @file
2 SCSI disk driver that layers on every SCSI IO protocol in the system.
3
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 1985 - 2022, American Megatrends International LLC.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "ScsiDisk.h"
11
12 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
13 ScsiDiskDriverBindingSupported,
14 ScsiDiskDriverBindingStart,
15 ScsiDiskDriverBindingStop,
16 0xa,
17 NULL,
18 NULL
19 };
20
21 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
22 EFI_DISK_INFO_SCSI_INTERFACE_GUID,
23 ScsiDiskInfoInquiry,
24 ScsiDiskInfoIdentify,
25 ScsiDiskInfoSenseData,
26 ScsiDiskInfoWhichIde
27 };
28
29 /**
30 Allocates an aligned buffer for SCSI disk.
31
32 This function allocates an aligned buffer for the SCSI disk to perform
33 SCSI IO operations. The alignment requirement is from SCSI IO interface.
34
35 @param ScsiDiskDevice The SCSI disk involved for the operation.
36 @param BufferSize The request buffer size.
37
38 @return A pointer to the aligned buffer or NULL if the allocation fails.
39
40 **/
41 VOID *
42 AllocateAlignedBuffer (
43 IN SCSI_DISK_DEV *ScsiDiskDevice,
44 IN UINTN BufferSize
45 )
46 {
47 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);
48 }
49
50 /**
51 Frees an aligned buffer for SCSI disk.
52
53 This function frees an aligned buffer for the SCSI disk to perform
54 SCSI IO operations.
55
56 @param Buffer The aligned buffer to be freed.
57 @param BufferSize The request buffer size.
58
59 **/
60 VOID
61 FreeAlignedBuffer (
62 IN VOID *Buffer,
63 IN UINTN BufferSize
64 )
65 {
66 if (Buffer != NULL) {
67 FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
68 }
69 }
70
71 /**
72 Remove trailing spaces from the string.
73
74 @param String The ASCII string to remove the trailing spaces.
75
76 @retval the new length of the string.
77 **/
78 UINTN
79 RemoveTrailingSpaces (
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
98 /**
99 The user Entry Point for module ScsiDisk.
100
101 The user code starts with this function.
102
103 @param ImageHandle The firmware allocated handle for the EFI image.
104 @param SystemTable A pointer to the EFI System Table.
105
106 @retval EFI_SUCCESS The entry point is executed successfully.
107 @retval other Some error occurs when executing this entry point.
108
109 **/
110 EFI_STATUS
111 EFIAPI
112 InitializeScsiDisk (
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 //
122 Status = EfiLibInstallDriverBindingComponentName2 (
123 ImageHandle,
124 SystemTable,
125 &gScsiDiskDriverBinding,
126 ImageHandle,
127 &gScsiDiskComponentName,
128 &gScsiDiskComponentName2
129 );
130 ASSERT_EFI_ERROR (Status);
131
132 return Status;
133 }
134
135 /**
136 Test to see if this driver supports ControllerHandle.
137
138 This service is called by the EFI boot service ConnectController(). In order
139 to make drivers as small as possible, there are a few calling restrictions for
140 this service. ConnectController() must follow these calling restrictions.
141 If any other agent wishes to call Supported() it must also follow these
142 calling restrictions.
143
144 @param This Protocol instance pointer.
145 @param ControllerHandle Handle of device to test
146 @param RemainingDevicePath Optional parameter use to pick a specific child
147 device to start.
148
149 @retval EFI_SUCCESS This driver supports this device
150 @retval EFI_ALREADY_STARTED This driver is already running on this device
151 @retval other This driver does not support this device
152
153 **/
154 EFI_STATUS
155 EFIAPI
156 ScsiDiskDriverBindingSupported (
157 IN EFI_DRIVER_BINDING_PROTOCOL *This,
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
199 /**
200 Start this driver on ControllerHandle.
201
202 This service is called by the EFI boot service ConnectController(). In order
203 to make drivers as small as possible, there are a few calling restrictions for
204 this service. ConnectController() must follow these calling restrictions. If
205 any other agent wishes to call Start() it must also follow these calling
206 restrictions.
207
208 @param This Protocol instance pointer.
209 @param ControllerHandle Handle of device to bind driver to
210 @param RemainingDevicePath Optional parameter use to pick a specific child
211 device to start.
212
213 @retval EFI_SUCCESS This driver is added to ControllerHandle
214 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
215 @retval other This driver does not support this device
216
217 **/
218 EFI_STATUS
219 EFIAPI
220 ScsiDiskDriverBindingStart (
221 IN EFI_DRIVER_BINDING_PROTOCOL *This,
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) {
284 case EFI_SCSI_TYPE_DISK:
285 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
286 MustReadCapacity = TRUE;
287 break;
288
289 case EFI_SCSI_TYPE_CDROM:
290 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
291 ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;
292 MustReadCapacity = FALSE;
293 break;
294
295 case EFI_SCSI_TYPE_WLUN:
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,
368 EFI_NATIVE_INTERFACE,
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,
380 EFI_NATIVE_INTERFACE,
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;
407 AddUnicodeString2 (
408 "eng",
409 gScsiDiskComponentName.SupportedLanguages,
410 &ScsiDiskDevice->ControllerNameTable,
411 DeviceStr,
412 TRUE
413 );
414 AddUnicodeString2 (
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
437 /**
438 Stop this driver on ControllerHandle.
439
440 This service is called by the EFI boot service DisconnectController().
441 In order to make drivers as small as possible, there are a few calling
442 restrictions for this service. DisconnectController() must follow these
443 calling restrictions. If any other agent wishes to call Stop() it must
444 also follow these calling restrictions.
445
446 @param This Protocol instance pointer.
447 @param ControllerHandle Handle of device to stop driver on
448 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
449 children is zero stop the entire bus driver.
450 @param ChildHandleBuffer List of Child Handles to Stop.
451
452 @retval EFI_SUCCESS This driver is removed ControllerHandle
453 @retval other This driver was not removed from this device
454
455 **/
456 EFI_STATUS
457 EFIAPI
458 ScsiDiskDriverBindingStop (
459 IN EFI_DRIVER_BINDING_PROTOCOL *This,
460 IN EFI_HANDLE Controller,
461 IN UINTN NumberOfChildren,
462 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
463 )
464 {
465 EFI_BLOCK_IO_PROTOCOL *BlkIo;
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
542 /**
543 Reset SCSI Disk.
544
545
546 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
547 @param ExtendedVerification The flag about if extend verificate
548
549 @retval EFI_SUCCESS The device was reset.
550 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
551 not be reset.
552 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
553
554 **/
555 EFI_STATUS
556 EFIAPI
557 ScsiDiskReset (
558 IN EFI_BLOCK_IO_PROTOCOL *This,
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
592 Done:
593 gBS->RestoreTPL (OldTpl);
594 return Status;
595 }
596
597 /**
598 The function is to Read Block from SCSI Disk.
599
600 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
601 @param MediaId The Id of Media detected
602 @param Lba The logic block address
603 @param BufferSize The size of Buffer
604 @param Buffer The buffer to fill the read out data
605
606 @retval EFI_SUCCESS Successfully to read out block.
607 @retval EFI_DEVICE_ERROR Fail to detect media.
608 @retval EFI_NO_MEDIA Media is not present.
609 @retval EFI_MEDIA_CHANGED Media has changed.
610 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
611 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
612
613 **/
614 EFI_STATUS
615 EFIAPI
616 ScsiDiskReadBlocks (
617 IN EFI_BLOCK_IO_PROTOCOL *This,
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
743 Done:
744 gBS->RestoreTPL (OldTpl);
745 return Status;
746 }
747
748 /**
749 The function is to Write Block to SCSI Disk.
750
751 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
752 @param MediaId The Id of Media detected
753 @param Lba The logic block address
754 @param BufferSize The size of Buffer
755 @param Buffer The buffer to fill the read out data
756
757 @retval EFI_SUCCESS Successfully to read out block.
758 @retval EFI_WRITE_PROTECTED The device can not be written to.
759 @retval EFI_DEVICE_ERROR Fail to detect media.
760 @retval EFI_NO_MEDIA Media is not present.
761 @retval EFI_MEDIA_CHANGED Media has changed.
762 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
763 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
764
765 **/
766 EFI_STATUS
767 EFIAPI
768 ScsiDiskWriteBlocks (
769 IN EFI_BLOCK_IO_PROTOCOL *This,
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
900 Done:
901 gBS->RestoreTPL (OldTpl);
902 return Status;
903 }
904
905 /**
906 Flush Block to Disk.
907
908 EFI_SUCCESS is returned directly.
909
910 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
911
912 @retval EFI_SUCCESS All outstanding data was written to the device
913
914 **/
915 EFI_STATUS
916 EFIAPI
917 ScsiDiskFlushBlocks (
918 IN EFI_BLOCK_IO_PROTOCOL *This
919 )
920 {
921 //
922 // return directly
923 //
924 return EFI_SUCCESS;
925 }
926
927 /**
928 Reset SCSI Disk.
929
930 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
931 @param ExtendedVerification The flag about if extend verificate.
932
933 @retval EFI_SUCCESS The device was reset.
934 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
935 not be reset.
936 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
937
938 **/
939 EFI_STATUS
940 EFIAPI
941 ScsiDiskResetEx (
942 IN EFI_BLOCK_IO2_PROTOCOL *This,
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
976 Done:
977 gBS->RestoreTPL (OldTpl);
978 return Status;
979 }
980
981 /**
982 The function is to Read Block from SCSI Disk.
983
984 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
985 @param MediaId The Id of Media detected.
986 @param Lba The logic block address.
987 @param Token A pointer to the token associated with the transaction.
988 @param BufferSize The size of Buffer.
989 @param Buffer The buffer to fill the read out data.
990
991 @retval EFI_SUCCESS The read request was queued if Token-> Event is
992 not NULL. The data was read correctly from the
993 device if theToken-> Event is NULL.
994 @retval EFI_DEVICE_ERROR The device reported an error while attempting
995 to perform the read operation.
996 @retval EFI_NO_MEDIA There is no media in the device.
997 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
998 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
999 the intrinsic block size of the device.
1000 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
1001 valid, or the buffer is not on proper
1002 alignment.
1003 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
1004 lack of resources.
1005
1006 **/
1007 EFI_STATUS
1008 EFIAPI
1009 ScsiDiskReadBlocksEx (
1010 IN EFI_BLOCK_IO2_PROTOCOL *This,
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
1158 Done:
1159 gBS->RestoreTPL (OldTpl);
1160 return Status;
1161 }
1162
1163 /**
1164 The function is to Write Block to SCSI Disk.
1165
1166 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
1167 @param MediaId The Id of Media detected.
1168 @param Lba The logic block address.
1169 @param Token A pointer to the token associated with the transaction.
1170 @param BufferSize The size of Buffer.
1171 @param Buffer The buffer to fill the read out data.
1172
1173 @retval EFI_SUCCESS The data were written correctly to the device.
1174 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1175 @retval EFI_NO_MEDIA There is no media in the device.
1176 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1177 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1178 to perform the write operation.
1179 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1180 the intrinsic block size of the device.
1181 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1182 valid, or the buffer is not on proper
1183 alignment.
1184
1185 **/
1186 EFI_STATUS
1187 EFIAPI
1188 ScsiDiskWriteBlocksEx (
1189 IN EFI_BLOCK_IO2_PROTOCOL *This,
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
1342 Done:
1343 gBS->RestoreTPL (OldTpl);
1344 return Status;
1345 }
1346
1347 /**
1348 Flush the Block Device.
1349
1350 @param This Indicates a pointer to the calling context.
1351 @param Token A pointer to the token associated with the transaction.
1352
1353 @retval EFI_SUCCESS All outstanding data was written to the device.
1354 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1355 write data.
1356 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1357 @retval EFI_NO_MEDIA There is no media in the device.
1358 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1359
1360 **/
1361 EFI_STATUS
1362 EFIAPI
1363 ScsiDiskFlushBlocksEx (
1364 IN EFI_BLOCK_IO2_PROTOCOL *This,
1365 IN OUT EFI_BLOCK_IO2_TOKEN *Token
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
1453 Done:
1454 gBS->RestoreTPL (OldTpl);
1455 return Status;
1456 }
1457
1458 /**
1459 Internal helper notify function which process the result of an asynchronous
1460 SCSI UNMAP Command and signal the event passed from EraseBlocks.
1461
1462 @param Event The instance of EFI_EVENT.
1463 @param Context The parameter passed in.
1464
1465 **/
1466 VOID
1467 EFIAPI
1468 ScsiDiskAsyncUnmapNotify (
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
1509 Done:
1510 RemoveEntryList (&EraseBlkReq->Link);
1511 FreePool (CommandPacket->OutDataBuffer);
1512 FreePool (EraseBlkReq->CommandPacket.Cdb);
1513 FreePool (EraseBlkReq);
1514
1515 gBS->SignalEvent (Token->Event);
1516 }
1517
1518 /**
1519 Require the device server to cause one or more LBAs to be unmapped.
1520
1521 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
1522 @param Lba The start block number.
1523 @param Blocks Total block number to be unmapped.
1524 @param Token The pointer to the token associated with the
1525 non-blocking erase block request.
1526
1527 @retval EFI_SUCCESS Target blocks have been successfully unmapped.
1528 @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
1529
1530 **/
1531 EFI_STATUS
1532 ScsiDiskUnmap (
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;
1542 EFI_SCSI_DISK_UNMAP_BLOCK_DESP *BlkDespPtr;
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,
1627 ScsiDiskAsyncUnmapNotify,
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
1703 Done:
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
1723 /**
1724 Erase a specified number of device blocks.
1725
1726 @param[in] This Indicates a pointer to the calling context.
1727 @param[in] MediaId The media ID that the erase request is for.
1728 @param[in] Lba The starting logical block address to be
1729 erased. The caller is responsible for erasing
1730 only legitimate locations.
1731 @param[in, out] Token A pointer to the token associated with the
1732 transaction.
1733 @param[in] Size The size in bytes to be erased. This must be
1734 a multiple of the physical block size of the
1735 device.
1736
1737 @retval EFI_SUCCESS The erase request was queued if Event is not
1738 NULL. The data was erased correctly to the
1739 device if the Event is NULL.to the device.
1740 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1741 protection.
1742 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1743 to perform the erase operation.
1744 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1745 valid.
1746 @retval EFI_NO_MEDIA There is no media in the device.
1747 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1748
1749 **/
1750 EFI_STATUS
1751 EFIAPI
1752 ScsiDiskEraseBlocks (
1753 IN EFI_ERASE_BLOCK_PROTOCOL *This,
1754 IN UINT32 MediaId,
1755 IN EFI_LBA Lba,
1756 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
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
1863 Done:
1864 gBS->RestoreTPL (OldTpl);
1865 return Status;
1866 }
1867
1868 /**
1869 Send a security protocol command to a device that receives data and/or the result
1870 of one or more commands sent by SendData.
1871
1872 The ReceiveData function sends a security protocol command to the given MediaId.
1873 The security protocol command sent is defined by SecurityProtocolId and contains
1874 the security protocol specific data SecurityProtocolSpecificData. The function
1875 returns the data from the security protocol command in PayloadBuffer.
1876
1877 For devices supporting the SCSI command set, the security protocol command is sent
1878 using the SECURITY PROTOCOL IN command defined in SPC-4.
1879
1880 If PayloadBufferSize is too small to store the available data from the security
1881 protocol command, the function shall copy PayloadBufferSize bytes into the
1882 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1883
1884 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1885 the function shall return EFI_INVALID_PARAMETER.
1886
1887 If the given MediaId does not support security protocol commands, the function shall
1888 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1889 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1890 the function returns EFI_MEDIA_CHANGED.
1891
1892 If the security protocol fails to complete within the Timeout period, the function
1893 shall return EFI_TIMEOUT.
1894
1895 If the security protocol command completes without an error, the function shall
1896 return EFI_SUCCESS. If the security protocol command completes with an error, the
1897 function shall return EFI_DEVICE_ERROR.
1898
1899 @param This Indicates a pointer to the calling context.
1900 @param MediaId ID of the medium to receive data from.
1901 @param Timeout The timeout, in 100ns units, to use for the execution
1902 of the security protocol command. A Timeout value of 0
1903 means that this function will wait indefinitely for the
1904 security protocol command to execute. If Timeout is greater
1905 than zero, then this function will return EFI_TIMEOUT if the
1906 time required to execute the receive data command is greater than Timeout.
1907 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1908 the security protocol command to be sent.
1909 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1910 of the security protocol command to be sent.
1911 @param PayloadBufferSize Size in bytes of the payload data buffer.
1912 @param PayloadBuffer A pointer to a destination buffer to store the security
1913 protocol command specific payload data for the security
1914 protocol command. The caller is responsible for having
1915 either implicit or explicit ownership of the buffer.
1916 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1917 data written to the payload data buffer.
1918
1919 @retval EFI_SUCCESS The security protocol command completed successfully.
1920 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1921 data from the device. The PayloadBuffer contains the truncated data.
1922 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1923 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1924 @retval EFI_NO_MEDIA There is no media in the device.
1925 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1926 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1927 PayloadBufferSize is non-zero.
1928 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1929 protocol command to execute.
1930
1931 **/
1932 EFI_STATUS
1933 EFIAPI
1934 ScsiDiskReceiveData (
1935 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1936 IN UINT32 MediaId OPTIONAL,
1937 IN UINT64 Timeout,
1938 IN UINT8 SecurityProtocolId,
1939 IN UINT16 SecurityProtocolSpecificData,
1940 IN UINTN PayloadBufferSize,
1941 OUT VOID *PayloadBuffer,
1942 OUT UINTN *PayloadTransferSize
1943 )
1944 {
1945 SCSI_DISK_DEV *ScsiDiskDevice;
1946 EFI_BLOCK_IO_MEDIA *Media;
1947 EFI_STATUS Status;
1948 BOOLEAN MediaChange;
1949 EFI_TPL OldTpl;
1950 UINT8 SenseDataLength;
1951 UINT8 HostAdapterStatus;
1952 UINT8 TargetStatus;
1953 VOID *AlignedBuffer;
1954 BOOLEAN AlignedBufferAllocated;
1955
1956 AlignedBuffer = NULL;
1957 MediaChange = FALSE;
1958 AlignedBufferAllocated = FALSE;
1959 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1960 ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
1961 Media = ScsiDiskDevice->BlkIo.Media;
1962
1963 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
1964
1965 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
1966 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1967 if (EFI_ERROR (Status)) {
1968 Status = EFI_DEVICE_ERROR;
1969 goto Done;
1970 }
1971
1972 if (MediaChange) {
1973 gBS->ReinstallProtocolInterface (
1974 ScsiDiskDevice->Handle,
1975 &gEfiBlockIoProtocolGuid,
1976 &ScsiDiskDevice->BlkIo,
1977 &ScsiDiskDevice->BlkIo
1978 );
1979 gBS->ReinstallProtocolInterface (
1980 ScsiDiskDevice->Handle,
1981 &gEfiBlockIo2ProtocolGuid,
1982 &ScsiDiskDevice->BlkIo2,
1983 &ScsiDiskDevice->BlkIo2
1984 );
1985 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1986 gBS->ReinstallProtocolInterface (
1987 ScsiDiskDevice->Handle,
1988 &gEfiEraseBlockProtocolGuid,
1989 &ScsiDiskDevice->EraseBlock,
1990 &ScsiDiskDevice->EraseBlock
1991 );
1992 }
1993
1994 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1995 gBS->ReinstallProtocolInterface (
1996 ScsiDiskDevice->Handle,
1997 &gEfiStorageSecurityCommandProtocolGuid,
1998 &ScsiDiskDevice->StorageSecurity,
1999 &ScsiDiskDevice->StorageSecurity
2000 );
2001 }
2002
2003 if (Media->MediaPresent) {
2004 Status = EFI_MEDIA_CHANGED;
2005 } else {
2006 Status = EFI_NO_MEDIA;
2007 }
2008
2009 goto Done;
2010 }
2011 }
2012
2013 //
2014 // Validate Media
2015 //
2016 if (!(Media->MediaPresent)) {
2017 Status = EFI_NO_MEDIA;
2018 goto Done;
2019 }
2020
2021 if ((MediaId != 0) && (MediaId != Media->MediaId)) {
2022 Status = EFI_MEDIA_CHANGED;
2023 goto Done;
2024 }
2025
2026 if (PayloadBufferSize != 0) {
2027 if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL)) {
2028 Status = EFI_INVALID_PARAMETER;
2029 goto Done;
2030 }
2031
2032 if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
2033 AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
2034 if (AlignedBuffer == NULL) {
2035 Status = EFI_OUT_OF_RESOURCES;
2036 goto Done;
2037 }
2038
2039 ZeroMem (AlignedBuffer, PayloadBufferSize);
2040 AlignedBufferAllocated = TRUE;
2041 } else {
2042 AlignedBuffer = PayloadBuffer;
2043 }
2044 }
2045
2046 Status = ScsiSecurityProtocolInCommand (
2047 ScsiDiskDevice->ScsiIo,
2048 Timeout,
2049 ScsiDiskDevice->SenseData,
2050 &SenseDataLength,
2051 &HostAdapterStatus,
2052 &TargetStatus,
2053 SecurityProtocolId,
2054 SecurityProtocolSpecificData,
2055 FALSE,
2056 PayloadBufferSize,
2057 AlignedBuffer,
2058 PayloadTransferSize
2059 );
2060 if (EFI_ERROR (Status)) {
2061 goto Done;
2062 }
2063
2064 if (AlignedBufferAllocated) {
2065 CopyMem (PayloadBuffer, AlignedBuffer, PayloadBufferSize);
2066 }
2067
2068 if (PayloadBufferSize < *PayloadTransferSize) {
2069 Status = EFI_WARN_BUFFER_TOO_SMALL;
2070 goto Done;
2071 }
2072
2073 Status = CheckHostAdapterStatus (HostAdapterStatus);
2074 if (EFI_ERROR (Status)) {
2075 goto Done;
2076 }
2077
2078 Status = CheckTargetStatus (TargetStatus);
2079 if (EFI_ERROR (Status)) {
2080 goto Done;
2081 }
2082
2083 Done:
2084 if (AlignedBufferAllocated) {
2085 ZeroMem (AlignedBuffer, PayloadBufferSize);
2086 FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
2087 }
2088
2089 gBS->RestoreTPL (OldTpl);
2090 return Status;
2091 }
2092
2093 /**
2094 Send a security protocol command to a device.
2095
2096 The SendData function sends a security protocol command containing the payload
2097 PayloadBuffer to the given MediaId. The security protocol command sent is
2098 defined by SecurityProtocolId and contains the security protocol specific data
2099 SecurityProtocolSpecificData. If the underlying protocol command requires a
2100 specific padding for the command payload, the SendData function shall add padding
2101 bytes to the command payload to satisfy the padding requirements.
2102
2103 For devices supporting the SCSI command set, the security protocol command is sent
2104 using the SECURITY PROTOCOL OUT command defined in SPC-4.
2105
2106 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
2107 return EFI_INVALID_PARAMETER.
2108
2109 If the given MediaId does not support security protocol commands, the function
2110 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
2111 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
2112 device, the function returns EFI_MEDIA_CHANGED.
2113
2114 If the security protocol fails to complete within the Timeout period, the function
2115 shall return EFI_TIMEOUT.
2116
2117 If the security protocol command completes without an error, the function shall return
2118 EFI_SUCCESS. If the security protocol command completes with an error, the function
2119 shall return EFI_DEVICE_ERROR.
2120
2121 @param This Indicates a pointer to the calling context.
2122 @param MediaId ID of the medium to receive data from.
2123 @param Timeout The timeout, in 100ns units, to use for the execution
2124 of the security protocol command. A Timeout value of 0
2125 means that this function will wait indefinitely for the
2126 security protocol command to execute. If Timeout is greater
2127 than zero, then this function will return EFI_TIMEOUT if the
2128 time required to execute the receive data command is greater than Timeout.
2129 @param SecurityProtocolId The value of the "Security Protocol" parameter of
2130 the security protocol command to be sent.
2131 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
2132 of the security protocol command to be sent.
2133 @param PayloadBufferSize Size in bytes of the payload data buffer.
2134 @param PayloadBuffer A pointer to a destination buffer to store the security
2135 protocol command specific payload data for the security
2136 protocol command.
2137
2138 @retval EFI_SUCCESS The security protocol command completed successfully.
2139 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
2140 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
2141 @retval EFI_NO_MEDIA There is no media in the device.
2142 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
2143 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
2144 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
2145 protocol command to execute.
2146
2147 **/
2148 EFI_STATUS
2149 EFIAPI
2150 ScsiDiskSendData (
2151 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
2152 IN UINT32 MediaId OPTIONAL,
2153 IN UINT64 Timeout,
2154 IN UINT8 SecurityProtocolId,
2155 IN UINT16 SecurityProtocolSpecificData,
2156 IN UINTN PayloadBufferSize,
2157 OUT VOID *PayloadBuffer
2158 )
2159 {
2160 SCSI_DISK_DEV *ScsiDiskDevice;
2161 EFI_BLOCK_IO_MEDIA *Media;
2162 EFI_STATUS Status;
2163 BOOLEAN MediaChange;
2164 EFI_TPL OldTpl;
2165 UINT8 SenseDataLength;
2166 UINT8 HostAdapterStatus;
2167 UINT8 TargetStatus;
2168 VOID *AlignedBuffer;
2169 BOOLEAN AlignedBufferAllocated;
2170
2171 AlignedBuffer = NULL;
2172 MediaChange = FALSE;
2173 AlignedBufferAllocated = FALSE;
2174 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2175 ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
2176 Media = ScsiDiskDevice->BlkIo.Media;
2177
2178 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2179
2180 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
2181 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
2182 if (EFI_ERROR (Status)) {
2183 Status = EFI_DEVICE_ERROR;
2184 goto Done;
2185 }
2186
2187 if (MediaChange) {
2188 gBS->ReinstallProtocolInterface (
2189 ScsiDiskDevice->Handle,
2190 &gEfiBlockIoProtocolGuid,
2191 &ScsiDiskDevice->BlkIo,
2192 &ScsiDiskDevice->BlkIo
2193 );
2194 gBS->ReinstallProtocolInterface (
2195 ScsiDiskDevice->Handle,
2196 &gEfiBlockIo2ProtocolGuid,
2197 &ScsiDiskDevice->BlkIo2,
2198 &ScsiDiskDevice->BlkIo2
2199 );
2200 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
2201 gBS->ReinstallProtocolInterface (
2202 ScsiDiskDevice->Handle,
2203 &gEfiEraseBlockProtocolGuid,
2204 &ScsiDiskDevice->EraseBlock,
2205 &ScsiDiskDevice->EraseBlock
2206 );
2207 }
2208
2209 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
2210 gBS->ReinstallProtocolInterface (
2211 ScsiDiskDevice->Handle,
2212 &gEfiStorageSecurityCommandProtocolGuid,
2213 &ScsiDiskDevice->StorageSecurity,
2214 &ScsiDiskDevice->StorageSecurity
2215 );
2216 }
2217
2218 if (Media->MediaPresent) {
2219 Status = EFI_MEDIA_CHANGED;
2220 } else {
2221 Status = EFI_NO_MEDIA;
2222 }
2223
2224 goto Done;
2225 }
2226 }
2227
2228 //
2229 // Validate Media
2230 //
2231 if (!(Media->MediaPresent)) {
2232 Status = EFI_NO_MEDIA;
2233 goto Done;
2234 }
2235
2236 if ((MediaId != 0) && (MediaId != Media->MediaId)) {
2237 Status = EFI_MEDIA_CHANGED;
2238 goto Done;
2239 }
2240
2241 if (Media->ReadOnly) {
2242 Status = EFI_WRITE_PROTECTED;
2243 goto Done;
2244 }
2245
2246 if (PayloadBufferSize != 0) {
2247 if (PayloadBuffer == NULL) {
2248 Status = EFI_INVALID_PARAMETER;
2249 goto Done;
2250 }
2251
2252 if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
2253 AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
2254 if (AlignedBuffer == NULL) {
2255 Status = EFI_OUT_OF_RESOURCES;
2256 goto Done;
2257 }
2258
2259 CopyMem (AlignedBuffer, PayloadBuffer, PayloadBufferSize);
2260 AlignedBufferAllocated = TRUE;
2261 } else {
2262 AlignedBuffer = PayloadBuffer;
2263 }
2264 }
2265
2266 Status = ScsiSecurityProtocolOutCommand (
2267 ScsiDiskDevice->ScsiIo,
2268 Timeout,
2269 ScsiDiskDevice->SenseData,
2270 &SenseDataLength,
2271 &HostAdapterStatus,
2272 &TargetStatus,
2273 SecurityProtocolId,
2274 SecurityProtocolSpecificData,
2275 FALSE,
2276 PayloadBufferSize,
2277 AlignedBuffer
2278 );
2279 if (EFI_ERROR (Status)) {
2280 goto Done;
2281 }
2282
2283 Status = CheckHostAdapterStatus (HostAdapterStatus);
2284 if (EFI_ERROR (Status)) {
2285 goto Done;
2286 }
2287
2288 Status = CheckTargetStatus (TargetStatus);
2289 if (EFI_ERROR (Status)) {
2290 goto Done;
2291 }
2292
2293 Done:
2294 if (AlignedBufferAllocated) {
2295 ZeroMem (AlignedBuffer, PayloadBufferSize);
2296 FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
2297 }
2298
2299 gBS->RestoreTPL (OldTpl);
2300 return Status;
2301 }
2302
2303 /**
2304 Detect Device and read out capacity ,if error occurs, parse the sense key.
2305
2306 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2307 @param MustReadCapacity The flag about reading device capacity
2308 @param MediaChange The pointer of flag indicates if media has changed
2309
2310 @retval EFI_DEVICE_ERROR Indicates that error occurs
2311 @retval EFI_SUCCESS Successfully to detect media
2312
2313 **/
2314 EFI_STATUS
2315 ScsiDiskDetectMedia (
2316 IN SCSI_DISK_DEV *ScsiDiskDevice,
2317 IN BOOLEAN MustReadCapacity,
2318 OUT BOOLEAN *MediaChange
2319 )
2320 {
2321 EFI_STATUS Status;
2322 EFI_SCSI_SENSE_DATA *SenseData;
2323 UINTN NumberOfSenseKeys;
2324 BOOLEAN NeedRetry;
2325 BOOLEAN NeedReadCapacity;
2326 UINT8 Retry;
2327 UINT8 MaxRetry;
2328 EFI_BLOCK_IO_MEDIA OldMedia;
2329 UINTN Action;
2330 EFI_EVENT TimeoutEvt;
2331
2332 Status = EFI_SUCCESS;
2333 SenseData = NULL;
2334 NumberOfSenseKeys = 0;
2335 Retry = 0;
2336 MaxRetry = 3;
2337 Action = ACTION_NO_ACTION;
2338 NeedReadCapacity = FALSE;
2339 *MediaChange = FALSE;
2340 TimeoutEvt = NULL;
2341
2342 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
2343
2344 Status = gBS->CreateEvent (
2345 EVT_TIMER,
2346 TPL_CALLBACK,
2347 NULL,
2348 NULL,
2349 &TimeoutEvt
2350 );
2351 if (EFI_ERROR (Status)) {
2352 return Status;
2353 }
2354
2355 Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS (120));
2356 if (EFI_ERROR (Status)) {
2357 goto EXIT;
2358 }
2359
2360 //
2361 // Sending Test_Unit cmd to poll device status.
2362 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
2363 // We limit the upper boundary to 120 seconds.
2364 //
2365 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
2366 Status = ScsiDiskTestUnitReady (
2367 ScsiDiskDevice,
2368 &NeedRetry,
2369 &SenseData,
2370 &NumberOfSenseKeys
2371 );
2372 if (!EFI_ERROR (Status)) {
2373 Status = DetectMediaParsingSenseKeys (
2374 ScsiDiskDevice,
2375 SenseData,
2376 NumberOfSenseKeys,
2377 &Action
2378 );
2379 if (EFI_ERROR (Status)) {
2380 goto EXIT;
2381 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
2382 continue;
2383 } else {
2384 break;
2385 }
2386 } else {
2387 Retry++;
2388 if (!NeedRetry || (Retry >= MaxRetry)) {
2389 goto EXIT;
2390 }
2391 }
2392 }
2393
2394 if (EFI_ERROR (Status)) {
2395 goto EXIT;
2396 }
2397
2398 //
2399 // ACTION_NO_ACTION: need not read capacity
2400 // other action code: need read capacity
2401 //
2402 if (Action == ACTION_READ_CAPACITY) {
2403 NeedReadCapacity = TRUE;
2404 }
2405
2406 //
2407 // READ_CAPACITY command is not supported by any of the UFS WLUNs.
2408 //
2409 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
2410 NeedReadCapacity = FALSE;
2411 MustReadCapacity = FALSE;
2412 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
2413 }
2414
2415 //
2416 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
2417 // retrieve capacity via Read Capacity command
2418 //
2419 if (NeedReadCapacity || MustReadCapacity) {
2420 //
2421 // retrieve media information
2422 //
2423 for (Retry = 0; Retry < MaxRetry; Retry++) {
2424 Status = ScsiDiskReadCapacity (
2425 ScsiDiskDevice,
2426 &NeedRetry,
2427 &SenseData,
2428 &NumberOfSenseKeys
2429 );
2430 if (!EFI_ERROR (Status)) {
2431 //
2432 // analyze sense key to action
2433 //
2434 Status = DetectMediaParsingSenseKeys (
2435 ScsiDiskDevice,
2436 SenseData,
2437 NumberOfSenseKeys,
2438 &Action
2439 );
2440 if (EFI_ERROR (Status)) {
2441 //
2442 // if Status is error, it may indicate crisis error,
2443 // so return without retry.
2444 //
2445 goto EXIT;
2446 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
2447 Retry = 0;
2448 continue;
2449 } else {
2450 break;
2451 }
2452 } else {
2453 Retry++;
2454 if (!NeedRetry || (Retry >= MaxRetry)) {
2455 goto EXIT;
2456 }
2457 }
2458 }
2459
2460 if (EFI_ERROR (Status)) {
2461 goto EXIT;
2462 }
2463 }
2464
2465 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
2466 //
2467 // Media change information got from the device
2468 //
2469 *MediaChange = TRUE;
2470 }
2471
2472 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
2473 *MediaChange = TRUE;
2474 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2475 }
2476
2477 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
2478 *MediaChange = TRUE;
2479 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2480 }
2481
2482 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
2483 *MediaChange = TRUE;
2484 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2485 }
2486
2487 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
2488 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
2489 //
2490 // when change from no media to media present, reset the MediaId to 1.
2491 //
2492 ScsiDiskDevice->BlkIo.Media->MediaId = 1;
2493 } else {
2494 //
2495 // when no media, reset the MediaId to zero.
2496 //
2497 ScsiDiskDevice->BlkIo.Media->MediaId = 0;
2498 }
2499
2500 *MediaChange = TRUE;
2501 }
2502
2503 EXIT:
2504 if (TimeoutEvt != NULL) {
2505 gBS->CloseEvent (TimeoutEvt);
2506 }
2507
2508 return Status;
2509 }
2510
2511 /**
2512 Send out Inquiry command to Device.
2513
2514 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2515 @param NeedRetry Indicates if needs try again when error happens
2516
2517 @retval EFI_DEVICE_ERROR Indicates that error occurs
2518 @retval EFI_SUCCESS Successfully to detect media
2519
2520 **/
2521 EFI_STATUS
2522 ScsiDiskInquiryDevice (
2523 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
2524 OUT BOOLEAN *NeedRetry
2525 )
2526 {
2527 UINT32 InquiryDataLength;
2528 UINT8 SenseDataLength;
2529 UINT8 HostAdapterStatus;
2530 UINT8 TargetStatus;
2531 EFI_SCSI_SENSE_DATA *SenseDataArray;
2532 UINTN NumberOfSenseKeys;
2533 EFI_STATUS Status;
2534 UINT8 MaxRetry;
2535 UINT8 Index;
2536 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
2537 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;
2538 UINTN PageLength;
2539
2540 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
2541 SenseDataLength = 0;
2542
2543 Status = ScsiInquiryCommand (
2544 ScsiDiskDevice->ScsiIo,
2545 SCSI_DISK_TIMEOUT,
2546 NULL,
2547 &SenseDataLength,
2548 &HostAdapterStatus,
2549 &TargetStatus,
2550 (VOID *)&(ScsiDiskDevice->InquiryData),
2551 &InquiryDataLength,
2552 FALSE
2553 );
2554 //
2555 // no need to check HostAdapterStatus and TargetStatus
2556 //
2557 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
2558 ParseInquiryData (ScsiDiskDevice);
2559
2560 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
2561 //
2562 // Check whether the device supports Block Limits VPD page (0xB0)
2563 //
2564 SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2565 if (SupportedVpdPages == NULL) {
2566 *NeedRetry = FALSE;
2567 return EFI_DEVICE_ERROR;
2568 }
2569
2570 ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2571 InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
2572 SenseDataLength = 0;
2573 Status = ScsiInquiryCommandEx (
2574 ScsiDiskDevice->ScsiIo,
2575 SCSI_DISK_TIMEOUT,
2576 NULL,
2577 &SenseDataLength,
2578 &HostAdapterStatus,
2579 &TargetStatus,
2580 (VOID *)SupportedVpdPages,
2581 &InquiryDataLength,
2582 TRUE,
2583 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2584 );
2585 if (!EFI_ERROR (Status)) {
2586 PageLength = (SupportedVpdPages->PageLength2 << 8)
2587 | SupportedVpdPages->PageLength1;
2588
2589 //
2590 // Sanity checks for coping with broken devices
2591 //
2592 if (PageLength > sizeof SupportedVpdPages->SupportedVpdPageList) {
2593 DEBUG ((
2594 DEBUG_WARN,
2595 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
2596 __FUNCTION__,
2597 (UINT32)PageLength
2598 ));
2599 PageLength = 0;
2600 }
2601
2602 if ((PageLength > 0) &&
2603 (SupportedVpdPages->SupportedVpdPageList[0] !=
2604 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD))
2605 {
2606 DEBUG ((
2607 DEBUG_WARN,
2608 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2609 __FUNCTION__,
2610 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2611 ));
2612 PageLength = 0;
2613 }
2614
2615 //
2616 // Locate the code for the Block Limits VPD page
2617 //
2618 for (Index = 0; Index < PageLength; Index++) {
2619 //
2620 // Sanity check
2621 //
2622 if ((Index > 0) &&
2623 (SupportedVpdPages->SupportedVpdPageList[Index] <=
2624 SupportedVpdPages->SupportedVpdPageList[Index - 1]))
2625 {
2626 DEBUG ((
2627 DEBUG_WARN,
2628 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2629 __FUNCTION__,
2630 Index
2631 ));
2632 Index = 0;
2633 PageLength = 0;
2634 break;
2635 }
2636
2637 if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
2638 break;
2639 }
2640 }
2641
2642 //
2643 // Query the Block Limits VPD page
2644 //
2645 if (Index < PageLength) {
2646 BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2647 if (BlockLimits == NULL) {
2648 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2649 *NeedRetry = FALSE;
2650 return EFI_DEVICE_ERROR;
2651 }
2652
2653 ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2654 InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
2655 SenseDataLength = 0;
2656 Status = ScsiInquiryCommandEx (
2657 ScsiDiskDevice->ScsiIo,
2658 SCSI_DISK_TIMEOUT,
2659 NULL,
2660 &SenseDataLength,
2661 &HostAdapterStatus,
2662 &TargetStatus,
2663 (VOID *)BlockLimits,
2664 &InquiryDataLength,
2665 TRUE,
2666 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2667 );
2668 if (!EFI_ERROR (Status)) {
2669 ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
2670 (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
2671 BlockLimits->OptimalTransferLengthGranularity1;
2672
2673 ScsiDiskDevice->UnmapInfo.MaxLbaCnt =
2674 (BlockLimits->MaximumUnmapLbaCount4 << 24) |
2675 (BlockLimits->MaximumUnmapLbaCount3 << 16) |
2676 (BlockLimits->MaximumUnmapLbaCount2 << 8) |
2677 BlockLimits->MaximumUnmapLbaCount1;
2678 ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt =
2679 (BlockLimits->MaximumUnmapBlockDescriptorCount4 << 24) |
2680 (BlockLimits->MaximumUnmapBlockDescriptorCount3 << 16) |
2681 (BlockLimits->MaximumUnmapBlockDescriptorCount2 << 8) |
2682 BlockLimits->MaximumUnmapBlockDescriptorCount1;
2683 ScsiDiskDevice->EraseBlock.EraseLengthGranularity =
2684 (BlockLimits->OptimalUnmapGranularity4 << 24) |
2685 (BlockLimits->OptimalUnmapGranularity3 << 16) |
2686 (BlockLimits->OptimalUnmapGranularity2 << 8) |
2687 BlockLimits->OptimalUnmapGranularity1;
2688 if (BlockLimits->UnmapGranularityAlignmentValid != 0) {
2689 ScsiDiskDevice->UnmapInfo.GranularityAlignment =
2690 (BlockLimits->UnmapGranularityAlignment4 << 24) |
2691 (BlockLimits->UnmapGranularityAlignment3 << 16) |
2692 (BlockLimits->UnmapGranularityAlignment2 << 8) |
2693 BlockLimits->UnmapGranularityAlignment1;
2694 }
2695
2696 if (ScsiDiskDevice->EraseBlock.EraseLengthGranularity == 0) {
2697 //
2698 // A value of 0 indicates that the optimal unmap granularity is
2699 // not reported.
2700 //
2701 ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
2702 }
2703
2704 ScsiDiskDevice->BlockLimitsVpdSupported = TRUE;
2705 }
2706
2707 FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2708 }
2709 }
2710
2711 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2712 }
2713 }
2714
2715 if (!EFI_ERROR (Status)) {
2716 return EFI_SUCCESS;
2717 } else if (Status == EFI_NOT_READY) {
2718 *NeedRetry = TRUE;
2719 return EFI_DEVICE_ERROR;
2720 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2721 *NeedRetry = FALSE;
2722 return EFI_DEVICE_ERROR;
2723 }
2724
2725 //
2726 // go ahead to check HostAdapterStatus and TargetStatus
2727 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2728 //
2729
2730 Status = CheckHostAdapterStatus (HostAdapterStatus);
2731 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2732 *NeedRetry = TRUE;
2733 return EFI_DEVICE_ERROR;
2734 } else if (Status == EFI_DEVICE_ERROR) {
2735 //
2736 // reset the scsi channel
2737 //
2738 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2739 *NeedRetry = FALSE;
2740 return EFI_DEVICE_ERROR;
2741 }
2742
2743 Status = CheckTargetStatus (TargetStatus);
2744 if (Status == EFI_NOT_READY) {
2745 //
2746 // reset the scsi device
2747 //
2748 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2749 *NeedRetry = TRUE;
2750 return EFI_DEVICE_ERROR;
2751 } else if (Status == EFI_DEVICE_ERROR) {
2752 *NeedRetry = FALSE;
2753 return EFI_DEVICE_ERROR;
2754 }
2755
2756 //
2757 // if goes here, meant ScsiInquiryCommand() failed.
2758 // if ScsiDiskRequestSenseKeys() succeeds at last,
2759 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2760 //
2761 MaxRetry = 3;
2762 for (Index = 0; Index < MaxRetry; Index++) {
2763 Status = ScsiDiskRequestSenseKeys (
2764 ScsiDiskDevice,
2765 NeedRetry,
2766 &SenseDataArray,
2767 &NumberOfSenseKeys,
2768 TRUE
2769 );
2770 if (!EFI_ERROR (Status)) {
2771 *NeedRetry = TRUE;
2772 return EFI_DEVICE_ERROR;
2773 }
2774
2775 if (!*NeedRetry) {
2776 return EFI_DEVICE_ERROR;
2777 }
2778 }
2779
2780 //
2781 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2782 // set *NeedRetry = FALSE to avoid the outside caller try again.
2783 //
2784 *NeedRetry = FALSE;
2785 return EFI_DEVICE_ERROR;
2786 }
2787
2788 /**
2789 To test device.
2790
2791 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2792 When Test Unit Ready command encounters any error caused by host adapter or
2793 target, return error without retrieving Sense Keys.
2794
2795 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2796 @param NeedRetry The pointer of flag indicates try again
2797 @param SenseDataArray The pointer of an array of sense data
2798 @param NumberOfSenseKeys The pointer of the number of sense data array
2799
2800 @retval EFI_DEVICE_ERROR Indicates that error occurs
2801 @retval EFI_SUCCESS Successfully to test unit
2802
2803 **/
2804 EFI_STATUS
2805 ScsiDiskTestUnitReady (
2806 IN SCSI_DISK_DEV *ScsiDiskDevice,
2807 OUT BOOLEAN *NeedRetry,
2808 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
2809 OUT UINTN *NumberOfSenseKeys
2810 )
2811 {
2812 EFI_STATUS Status;
2813 UINT8 SenseDataLength;
2814 UINT8 HostAdapterStatus;
2815 UINT8 TargetStatus;
2816 UINT8 Index;
2817 UINT8 MaxRetry;
2818
2819 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2820 *NumberOfSenseKeys = 0;
2821
2822 //
2823 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2824 //
2825 Status = ScsiTestUnitReadyCommand (
2826 ScsiDiskDevice->ScsiIo,
2827 SCSI_DISK_TIMEOUT,
2828 ScsiDiskDevice->SenseData,
2829 &SenseDataLength,
2830 &HostAdapterStatus,
2831 &TargetStatus
2832 );
2833 //
2834 // no need to check HostAdapterStatus and TargetStatus
2835 //
2836 if (Status == EFI_NOT_READY) {
2837 *NeedRetry = TRUE;
2838 return EFI_DEVICE_ERROR;
2839 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2840 *NeedRetry = FALSE;
2841 return EFI_DEVICE_ERROR;
2842 }
2843
2844 //
2845 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2846 //
2847
2848 Status = CheckHostAdapterStatus (HostAdapterStatus);
2849 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2850 *NeedRetry = TRUE;
2851 return EFI_DEVICE_ERROR;
2852 } else if (Status == EFI_DEVICE_ERROR) {
2853 //
2854 // reset the scsi channel
2855 //
2856 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2857 *NeedRetry = FALSE;
2858 return EFI_DEVICE_ERROR;
2859 }
2860
2861 Status = CheckTargetStatus (TargetStatus);
2862 if (Status == EFI_NOT_READY) {
2863 //
2864 // reset the scsi device
2865 //
2866 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2867 *NeedRetry = TRUE;
2868 return EFI_DEVICE_ERROR;
2869 } else if (Status == EFI_DEVICE_ERROR) {
2870 *NeedRetry = FALSE;
2871 return EFI_DEVICE_ERROR;
2872 }
2873
2874 if (SenseDataLength != 0) {
2875 *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
2876 *SenseDataArray = ScsiDiskDevice->SenseData;
2877 return EFI_SUCCESS;
2878 }
2879
2880 MaxRetry = 3;
2881 for (Index = 0; Index < MaxRetry; Index++) {
2882 Status = ScsiDiskRequestSenseKeys (
2883 ScsiDiskDevice,
2884 NeedRetry,
2885 SenseDataArray,
2886 NumberOfSenseKeys,
2887 FALSE
2888 );
2889 if (!EFI_ERROR (Status)) {
2890 return EFI_SUCCESS;
2891 }
2892
2893 if (!*NeedRetry) {
2894 return EFI_DEVICE_ERROR;
2895 }
2896 }
2897
2898 //
2899 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2900 // set *NeedRetry = FALSE to avoid the outside caller try again.
2901 //
2902 *NeedRetry = FALSE;
2903 return EFI_DEVICE_ERROR;
2904 }
2905
2906 /**
2907 Parsing Sense Keys which got from request sense command.
2908
2909 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2910 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2911 @param NumberOfSenseKeys The number of sense key
2912 @param Action The pointer of action which indicates what is need to do next
2913
2914 @retval EFI_DEVICE_ERROR Indicates that error occurs
2915 @retval EFI_SUCCESS Successfully to complete the parsing
2916
2917 **/
2918 EFI_STATUS
2919 DetectMediaParsingSenseKeys (
2920 OUT SCSI_DISK_DEV *ScsiDiskDevice,
2921 IN EFI_SCSI_SENSE_DATA *SenseData,
2922 IN UINTN NumberOfSenseKeys,
2923 OUT UINTN *Action
2924 )
2925 {
2926 BOOLEAN RetryLater;
2927
2928 //
2929 // Default is to read capacity, unless..
2930 //
2931 *Action = ACTION_READ_CAPACITY;
2932
2933 if (NumberOfSenseKeys == 0) {
2934 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2935 *Action = ACTION_NO_ACTION;
2936 }
2937
2938 return EFI_SUCCESS;
2939 }
2940
2941 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
2942 //
2943 // No Sense Key returned from last submitted command
2944 //
2945 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2946 *Action = ACTION_NO_ACTION;
2947 }
2948
2949 return EFI_SUCCESS;
2950 }
2951
2952 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
2953 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
2954 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
2955 *Action = ACTION_NO_ACTION;
2956 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2957 return EFI_SUCCESS;
2958 }
2959
2960 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
2961 ScsiDiskDevice->BlkIo.Media->MediaId++;
2962 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2963 return EFI_SUCCESS;
2964 }
2965
2966 if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
2967 *Action = ACTION_RETRY_COMMAND_LATER;
2968 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2969 return EFI_SUCCESS;
2970 }
2971
2972 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
2973 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
2974 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2975 return EFI_DEVICE_ERROR;
2976 }
2977
2978 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
2979 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2980 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2981 return EFI_DEVICE_ERROR;
2982 }
2983
2984 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
2985 if (RetryLater) {
2986 *Action = ACTION_RETRY_COMMAND_LATER;
2987 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2988 return EFI_SUCCESS;
2989 }
2990
2991 *Action = ACTION_NO_ACTION;
2992 return EFI_DEVICE_ERROR;
2993 }
2994
2995 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2996 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
2997 return EFI_SUCCESS;
2998 }
2999
3000 /**
3001 Send read capacity command to device and get the device parameter.
3002
3003 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3004 @param NeedRetry The pointer of flag indicates if need a retry
3005 @param SenseDataArray The pointer of an array of sense data
3006 @param NumberOfSenseKeys The number of sense key
3007
3008 @retval EFI_DEVICE_ERROR Indicates that error occurs
3009 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
3010
3011 **/
3012 EFI_STATUS
3013 ScsiDiskReadCapacity (
3014 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
3015 OUT BOOLEAN *NeedRetry,
3016 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
3017 OUT UINTN *NumberOfSenseKeys
3018 )
3019 {
3020 UINT8 HostAdapterStatus;
3021 UINT8 TargetStatus;
3022 EFI_STATUS CommandStatus;
3023 EFI_STATUS Status;
3024 UINT8 Index;
3025 UINT8 MaxRetry;
3026 UINT8 SenseDataLength;
3027 UINT32 DataLength10;
3028 UINT32 DataLength16;
3029 EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
3030 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
3031
3032 CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3033 if (CapacityData10 == NULL) {
3034 *NeedRetry = FALSE;
3035 return EFI_DEVICE_ERROR;
3036 }
3037
3038 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3039 if (CapacityData16 == NULL) {
3040 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3041 *NeedRetry = FALSE;
3042 return EFI_DEVICE_ERROR;
3043 }
3044
3045 SenseDataLength = 0;
3046 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
3047 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
3048 ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3049 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3050
3051 *NumberOfSenseKeys = 0;
3052 *NeedRetry = FALSE;
3053
3054 //
3055 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
3056 // 16 byte command should be used to access large hard disk >2TB
3057 //
3058 CommandStatus = ScsiReadCapacityCommand (
3059 ScsiDiskDevice->ScsiIo,
3060 SCSI_DISK_TIMEOUT,
3061 NULL,
3062 &SenseDataLength,
3063 &HostAdapterStatus,
3064 &TargetStatus,
3065 (VOID *)CapacityData10,
3066 &DataLength10,
3067 FALSE
3068 );
3069
3070 ScsiDiskDevice->Cdb16Byte = FALSE;
3071 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
3072 (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff))
3073 {
3074 //
3075 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
3076 //
3077 ScsiDiskDevice->Cdb16Byte = TRUE;
3078 //
3079 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
3080 // and LowestAlignedLba
3081 //
3082 CommandStatus = ScsiReadCapacity16Command (
3083 ScsiDiskDevice->ScsiIo,
3084 SCSI_DISK_TIMEOUT,
3085 NULL,
3086 &SenseDataLength,
3087 &HostAdapterStatus,
3088 &TargetStatus,
3089 (VOID *)CapacityData16,
3090 &DataLength16,
3091 FALSE
3092 );
3093 }
3094
3095 //
3096 // no need to check HostAdapterStatus and TargetStatus
3097 //
3098 if (CommandStatus == EFI_SUCCESS) {
3099 GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
3100 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3101 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3102 return EFI_SUCCESS;
3103 }
3104
3105 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3106 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3107
3108 if (CommandStatus == EFI_NOT_READY) {
3109 *NeedRetry = TRUE;
3110 return EFI_DEVICE_ERROR;
3111 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
3112 *NeedRetry = FALSE;
3113 return EFI_DEVICE_ERROR;
3114 }
3115
3116 //
3117 // go ahead to check HostAdapterStatus and TargetStatus
3118 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3119 //
3120
3121 Status = CheckHostAdapterStatus (HostAdapterStatus);
3122 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3123 *NeedRetry = TRUE;
3124 return EFI_DEVICE_ERROR;
3125 } else if (Status == EFI_DEVICE_ERROR) {
3126 //
3127 // reset the scsi channel
3128 //
3129 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3130 *NeedRetry = FALSE;
3131 return EFI_DEVICE_ERROR;
3132 }
3133
3134 Status = CheckTargetStatus (TargetStatus);
3135 if (Status == EFI_NOT_READY) {
3136 //
3137 // reset the scsi device
3138 //
3139 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3140 *NeedRetry = TRUE;
3141 return EFI_DEVICE_ERROR;
3142 } else if (Status == EFI_DEVICE_ERROR) {
3143 *NeedRetry = FALSE;
3144 return EFI_DEVICE_ERROR;
3145 }
3146
3147 //
3148 // if goes here, meant ScsiReadCapacityCommand() failed.
3149 // if ScsiDiskRequestSenseKeys() succeeds at last,
3150 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
3151 //
3152 MaxRetry = 3;
3153 for (Index = 0; Index < MaxRetry; Index++) {
3154 Status = ScsiDiskRequestSenseKeys (
3155 ScsiDiskDevice,
3156 NeedRetry,
3157 SenseDataArray,
3158 NumberOfSenseKeys,
3159 TRUE
3160 );
3161 if (!EFI_ERROR (Status)) {
3162 return EFI_SUCCESS;
3163 }
3164
3165 if (!*NeedRetry) {
3166 return EFI_DEVICE_ERROR;
3167 }
3168 }
3169
3170 //
3171 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
3172 // set *NeedRetry = FALSE to avoid the outside caller try again.
3173 //
3174 *NeedRetry = FALSE;
3175 return EFI_DEVICE_ERROR;
3176 }
3177
3178 /**
3179 Check the HostAdapter status and re-interpret it in EFI_STATUS.
3180
3181 @param HostAdapterStatus Host Adapter status
3182
3183 @retval EFI_SUCCESS Host adapter is OK.
3184 @retval EFI_TIMEOUT Timeout.
3185 @retval EFI_NOT_READY Adapter NOT ready.
3186 @retval EFI_DEVICE_ERROR Adapter device error.
3187
3188 **/
3189 EFI_STATUS
3190 CheckHostAdapterStatus (
3191 IN UINT8 HostAdapterStatus
3192 )
3193 {
3194 switch (HostAdapterStatus) {
3195 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
3196 return EFI_SUCCESS;
3197
3198 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
3199 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
3200 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
3201 return EFI_TIMEOUT;
3202
3203 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
3204 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
3205 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
3206 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
3207 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
3208 return EFI_NOT_READY;
3209
3210 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
3211 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
3212 return EFI_DEVICE_ERROR;
3213
3214 default:
3215 return EFI_SUCCESS;
3216 }
3217 }
3218
3219 /**
3220 Check the target status and re-interpret it in EFI_STATUS.
3221
3222 @param TargetStatus Target status
3223
3224 @retval EFI_NOT_READY Device is NOT ready.
3225 @retval EFI_DEVICE_ERROR
3226 @retval EFI_SUCCESS
3227
3228 **/
3229 EFI_STATUS
3230 CheckTargetStatus (
3231 IN UINT8 TargetStatus
3232 )
3233 {
3234 switch (TargetStatus) {
3235 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
3236 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
3237 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
3238 return EFI_SUCCESS;
3239
3240 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
3241 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
3242 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
3243 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
3244 return EFI_NOT_READY;
3245
3246 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
3247 return EFI_DEVICE_ERROR;
3248
3249 default:
3250 return EFI_SUCCESS;
3251 }
3252 }
3253
3254 /**
3255 Retrieve all sense keys from the device.
3256
3257 When encountering error during the process, if retrieve sense keys before
3258 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
3259 and NeedRetry set to FALSE; otherwise, return the proper return status.
3260
3261 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3262 @param NeedRetry The pointer of flag indicates if need a retry
3263 @param SenseDataArray The pointer of an array of sense data
3264 @param NumberOfSenseKeys The number of sense key
3265 @param AskResetIfError The flag indicates if need reset when error occurs
3266
3267 @retval EFI_DEVICE_ERROR Indicates that error occurs
3268 @retval EFI_SUCCESS Successfully to request sense key
3269
3270 **/
3271 EFI_STATUS
3272 ScsiDiskRequestSenseKeys (
3273 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
3274 OUT BOOLEAN *NeedRetry,
3275 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
3276 OUT UINTN *NumberOfSenseKeys,
3277 IN BOOLEAN AskResetIfError
3278 )
3279 {
3280 EFI_SCSI_SENSE_DATA *PtrSenseData;
3281 UINT8 SenseDataLength;
3282 BOOLEAN SenseReq;
3283 EFI_STATUS Status;
3284 EFI_STATUS FallStatus;
3285 UINT8 HostAdapterStatus;
3286 UINT8 TargetStatus;
3287
3288 FallStatus = EFI_SUCCESS;
3289 SenseDataLength = (UINT8)sizeof (EFI_SCSI_SENSE_DATA);
3290
3291 ZeroMem (
3292 ScsiDiskDevice->SenseData,
3293 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
3294 );
3295
3296 *NumberOfSenseKeys = 0;
3297 *SenseDataArray = ScsiDiskDevice->SenseData;
3298 Status = EFI_SUCCESS;
3299 PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
3300 if (PtrSenseData == NULL) {
3301 return EFI_DEVICE_ERROR;
3302 }
3303
3304 for (SenseReq = TRUE; SenseReq;) {
3305 ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
3306 Status = ScsiRequestSenseCommand (
3307 ScsiDiskDevice->ScsiIo,
3308 SCSI_DISK_TIMEOUT,
3309 PtrSenseData,
3310 &SenseDataLength,
3311 &HostAdapterStatus,
3312 &TargetStatus
3313 );
3314 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
3315 FallStatus = EFI_SUCCESS;
3316 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3317 *NeedRetry = TRUE;
3318 FallStatus = EFI_DEVICE_ERROR;
3319 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
3320 *NeedRetry = FALSE;
3321 FallStatus = EFI_DEVICE_ERROR;
3322 } else if (Status == EFI_DEVICE_ERROR) {
3323 if (AskResetIfError) {
3324 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3325 }
3326
3327 FallStatus = EFI_DEVICE_ERROR;
3328 }
3329
3330 if (EFI_ERROR (FallStatus)) {
3331 if (*NumberOfSenseKeys != 0) {
3332 *NeedRetry = FALSE;
3333 Status = EFI_SUCCESS;
3334 goto EXIT;
3335 } else {
3336 Status = EFI_DEVICE_ERROR;
3337 goto EXIT;
3338 }
3339 }
3340
3341 CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
3342 (*NumberOfSenseKeys) += 1;
3343
3344 //
3345 // no more sense key or number of sense keys exceeds predefined,
3346 // skip the loop.
3347 //
3348 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
3349 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber))
3350 {
3351 SenseReq = FALSE;
3352 }
3353 }
3354
3355 EXIT:
3356 FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
3357 return Status;
3358 }
3359
3360 /**
3361 Get information from media read capacity command.
3362
3363 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3364 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
3365 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
3366
3367 **/
3368 VOID
3369 GetMediaInfo (
3370 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
3371 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
3372 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
3373 )
3374 {
3375 UINT8 *Ptr;
3376
3377 if (!ScsiDiskDevice->Cdb16Byte) {
3378 ScsiDiskDevice->BlkIo.Media->LastBlock = ((UINT32)Capacity10->LastLba3 << 24) |
3379 (Capacity10->LastLba2 << 16) |
3380 (Capacity10->LastLba1 << 8) |
3381 Capacity10->LastLba0;
3382
3383 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
3384 (Capacity10->BlockSize2 << 16) |
3385 (Capacity10->BlockSize1 << 8) |
3386 Capacity10->BlockSize0;
3387 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
3388 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;
3389 if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
3390 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;
3391 }
3392 } else {
3393 Ptr = (UINT8 *)&ScsiDiskDevice->BlkIo.Media->LastBlock;
3394 *Ptr++ = Capacity16->LastLba0;
3395 *Ptr++ = Capacity16->LastLba1;
3396 *Ptr++ = Capacity16->LastLba2;
3397 *Ptr++ = Capacity16->LastLba3;
3398 *Ptr++ = Capacity16->LastLba4;
3399 *Ptr++ = Capacity16->LastLba5;
3400 *Ptr++ = Capacity16->LastLba6;
3401 *Ptr = Capacity16->LastLba7;
3402
3403 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
3404 (Capacity16->BlockSize2 << 16) |
3405 (Capacity16->BlockSize1 << 8) |
3406 Capacity16->BlockSize0;
3407
3408 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
3409 Capacity16->LowestAlignLogic1;
3410 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);
3411 if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
3412 if (ScsiDiskDevice->BlkIo.Media->LastBlock > (UINT32)-1) {
3413 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)-1;
3414 } else {
3415 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;
3416 }
3417 }
3418 }
3419
3420 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
3421 }
3422
3423 /**
3424 Parse Inquiry data.
3425
3426 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3427
3428 **/
3429 VOID
3430 ParseInquiryData (
3431 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
3432 )
3433 {
3434 ScsiDiskDevice->FixedDevice = (BOOLEAN)((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
3435 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN)(!ScsiDiskDevice->FixedDevice);
3436 }
3437
3438 /**
3439 Read sector from SCSI Disk.
3440
3441 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3442 @param Buffer The buffer to fill in the read out data
3443 @param Lba Logic block address
3444 @param NumberOfBlocks The number of blocks to read
3445
3446 @retval EFI_DEVICE_ERROR Indicates a device error.
3447 @retval EFI_SUCCESS Operation is successful.
3448
3449 **/
3450 EFI_STATUS
3451 ScsiDiskReadSectors (
3452 IN SCSI_DISK_DEV *ScsiDiskDevice,
3453 OUT VOID *Buffer,
3454 IN EFI_LBA Lba,
3455 IN UINTN NumberOfBlocks
3456 )
3457 {
3458 UINTN BlocksRemaining;
3459 UINT8 *PtrBuffer;
3460 UINT32 BlockSize;
3461 UINT32 ByteCount;
3462 UINT32 MaxBlock;
3463 UINT32 SectorCount;
3464 UINT32 NextSectorCount;
3465 UINT64 Timeout;
3466 EFI_STATUS Status;
3467 UINT8 Index;
3468 UINT8 MaxRetry;
3469 BOOLEAN NeedRetry;
3470
3471 Status = EFI_SUCCESS;
3472
3473 BlocksRemaining = NumberOfBlocks;
3474 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
3475
3476 //
3477 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3478 //
3479 if (!ScsiDiskDevice->Cdb16Byte) {
3480 MaxBlock = 0xFFFF;
3481 } else {
3482 MaxBlock = 0xFFFFFFFF;
3483 }
3484
3485 PtrBuffer = Buffer;
3486
3487 while (BlocksRemaining > 0) {
3488 if (BlocksRemaining <= MaxBlock) {
3489 if (!ScsiDiskDevice->Cdb16Byte) {
3490 SectorCount = (UINT16)BlocksRemaining;
3491 } else {
3492 SectorCount = (UINT32)BlocksRemaining;
3493 }
3494 } else {
3495 SectorCount = MaxBlock;
3496 }
3497
3498 ByteCount = SectorCount * BlockSize;
3499 //
3500 // |------------------------|-----------------|------------------|-----------------|
3501 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3502 // |------------------------|-----------------|------------------|-----------------|
3503 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3504 // |------------------------|-----------------|------------------|-----------------|
3505 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3506 // |------------------------|-----------------|------------------|-----------------|
3507 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3508 // |------------------------|-----------------|------------------|-----------------|
3509 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3510 // |------------------------|-----------------|------------------|-----------------|
3511 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3512 // |------------------------|-----------------|------------------|-----------------|
3513 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3514 // |------------------------|-----------------|------------------|-----------------|
3515 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3516 // |------------------------|-----------------|------------------|-----------------|
3517 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3518 // |------------------------|-----------------|------------------|-----------------|
3519 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3520 // |------------------------|-----------------|------------------|-----------------|
3521 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3522 // |------------------------|-----------------|------------------|-----------------|
3523 //
3524 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3525 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3526 // From the above table, we could know 2.1Mbytes per second is lowest one.
3527 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3528 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3529 // commands in the Standby/Idle mode.
3530 //
3531 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3532
3533 MaxRetry = 2;
3534 for (Index = 0; Index < MaxRetry; Index++) {
3535 if (!ScsiDiskDevice->Cdb16Byte) {
3536 Status = ScsiDiskRead10 (
3537 ScsiDiskDevice,
3538 &NeedRetry,
3539 Timeout,
3540 PtrBuffer,
3541 &ByteCount,
3542 (UINT32)Lba,
3543 SectorCount
3544 );
3545 } else {
3546 Status = ScsiDiskRead16 (
3547 ScsiDiskDevice,
3548 &NeedRetry,
3549 Timeout,
3550 PtrBuffer,
3551 &ByteCount,
3552 Lba,
3553 SectorCount
3554 );
3555 }
3556
3557 if (!EFI_ERROR (Status)) {
3558 break;
3559 }
3560
3561 if (!NeedRetry) {
3562 return EFI_DEVICE_ERROR;
3563 }
3564
3565 //
3566 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
3567 // lowered ByteCount on output, we must make sure that we lower
3568 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3569 // it is invalid to request more sectors in the CDB than the entire
3570 // transfer (ie. ByteCount) can carry.
3571 //
3572 // In addition, ByteCount is only expected to go down, or stay unchanged.
3573 // Therefore we don't need to update Timeout: the original timeout should
3574 // accommodate shorter transfers too.
3575 //
3576 NextSectorCount = ByteCount / BlockSize;
3577 if (NextSectorCount < SectorCount) {
3578 SectorCount = NextSectorCount;
3579 //
3580 // Account for any rounding down.
3581 //
3582 ByteCount = SectorCount * BlockSize;
3583 }
3584 }
3585
3586 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
3587 return EFI_DEVICE_ERROR;
3588 }
3589
3590 //
3591 // actual transferred sectors
3592 //
3593 SectorCount = ByteCount / BlockSize;
3594
3595 Lba += SectorCount;
3596 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3597 BlocksRemaining -= SectorCount;
3598 }
3599
3600 return EFI_SUCCESS;
3601 }
3602
3603 /**
3604 Write sector to SCSI Disk.
3605
3606 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3607 @param Buffer The buffer of data to be written into SCSI Disk
3608 @param Lba Logic block address
3609 @param NumberOfBlocks The number of blocks to read
3610
3611 @retval EFI_DEVICE_ERROR Indicates a device error.
3612 @retval EFI_SUCCESS Operation is successful.
3613
3614 **/
3615 EFI_STATUS
3616 ScsiDiskWriteSectors (
3617 IN SCSI_DISK_DEV *ScsiDiskDevice,
3618 IN VOID *Buffer,
3619 IN EFI_LBA Lba,
3620 IN UINTN NumberOfBlocks
3621 )
3622 {
3623 UINTN BlocksRemaining;
3624 UINT8 *PtrBuffer;
3625 UINT32 BlockSize;
3626 UINT32 ByteCount;
3627 UINT32 MaxBlock;
3628 UINT32 SectorCount;
3629 UINT32 NextSectorCount;
3630 UINT64 Timeout;
3631 EFI_STATUS Status;
3632 UINT8 Index;
3633 UINT8 MaxRetry;
3634 BOOLEAN NeedRetry;
3635
3636 Status = EFI_SUCCESS;
3637
3638 BlocksRemaining = NumberOfBlocks;
3639 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
3640
3641 //
3642 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3643 //
3644 if (!ScsiDiskDevice->Cdb16Byte) {
3645 MaxBlock = 0xFFFF;
3646 } else {
3647 MaxBlock = 0xFFFFFFFF;
3648 }
3649
3650 PtrBuffer = Buffer;
3651
3652 while (BlocksRemaining > 0) {
3653 if (BlocksRemaining <= MaxBlock) {
3654 if (!ScsiDiskDevice->Cdb16Byte) {
3655 SectorCount = (UINT16)BlocksRemaining;
3656 } else {
3657 SectorCount = (UINT32)BlocksRemaining;
3658 }
3659 } else {
3660 SectorCount = MaxBlock;
3661 }
3662
3663 ByteCount = SectorCount * BlockSize;
3664 //
3665 // |------------------------|-----------------|------------------|-----------------|
3666 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3667 // |------------------------|-----------------|------------------|-----------------|
3668 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3669 // |------------------------|-----------------|------------------|-----------------|
3670 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3671 // |------------------------|-----------------|------------------|-----------------|
3672 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3673 // |------------------------|-----------------|------------------|-----------------|
3674 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3675 // |------------------------|-----------------|------------------|-----------------|
3676 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3677 // |------------------------|-----------------|------------------|-----------------|
3678 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3679 // |------------------------|-----------------|------------------|-----------------|
3680 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3681 // |------------------------|-----------------|------------------|-----------------|
3682 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3683 // |------------------------|-----------------|------------------|-----------------|
3684 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3685 // |------------------------|-----------------|------------------|-----------------|
3686 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3687 // |------------------------|-----------------|------------------|-----------------|
3688 //
3689 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3690 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3691 // From the above table, we could know 2.1Mbytes per second is lowest one.
3692 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3693 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3694 // commands in the Standby/Idle mode.
3695 //
3696 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3697 MaxRetry = 2;
3698 for (Index = 0; Index < MaxRetry; Index++) {
3699 if (!ScsiDiskDevice->Cdb16Byte) {
3700 Status = ScsiDiskWrite10 (
3701 ScsiDiskDevice,
3702 &NeedRetry,
3703 Timeout,
3704 PtrBuffer,
3705 &ByteCount,
3706 (UINT32)Lba,
3707 SectorCount
3708 );
3709 } else {
3710 Status = ScsiDiskWrite16 (
3711 ScsiDiskDevice,
3712 &NeedRetry,
3713 Timeout,
3714 PtrBuffer,
3715 &ByteCount,
3716 Lba,
3717 SectorCount
3718 );
3719 }
3720
3721 if (!EFI_ERROR (Status)) {
3722 break;
3723 }
3724
3725 if (!NeedRetry) {
3726 return EFI_DEVICE_ERROR;
3727 }
3728
3729 //
3730 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3731 // has lowered ByteCount on output, we must make sure that we lower
3732 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3733 // it is invalid to request more sectors in the CDB than the entire
3734 // transfer (ie. ByteCount) can carry.
3735 //
3736 // In addition, ByteCount is only expected to go down, or stay unchanged.
3737 // Therefore we don't need to update Timeout: the original timeout should
3738 // accommodate shorter transfers too.
3739 //
3740 NextSectorCount = ByteCount / BlockSize;
3741 if (NextSectorCount < SectorCount) {
3742 SectorCount = NextSectorCount;
3743 //
3744 // Account for any rounding down.
3745 //
3746 ByteCount = SectorCount * BlockSize;
3747 }
3748 }
3749
3750 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
3751 return EFI_DEVICE_ERROR;
3752 }
3753
3754 //
3755 // actual transferred sectors
3756 //
3757 SectorCount = ByteCount / BlockSize;
3758
3759 Lba += SectorCount;
3760 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3761 BlocksRemaining -= SectorCount;
3762 }
3763
3764 return EFI_SUCCESS;
3765 }
3766
3767 /**
3768 Asynchronously read sector from SCSI Disk.
3769
3770 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3771 @param Buffer The buffer to fill in the read out data.
3772 @param Lba Logic block address.
3773 @param NumberOfBlocks The number of blocks to read.
3774 @param Token A pointer to the token associated with the
3775 non-blocking read request.
3776
3777 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
3778 @retval EFI_DEVICE_ERROR Indicates a device error.
3779 @retval EFI_SUCCESS Operation is successful.
3780
3781 **/
3782 EFI_STATUS
3783 ScsiDiskAsyncReadSectors (
3784 IN SCSI_DISK_DEV *ScsiDiskDevice,
3785 OUT VOID *Buffer,
3786 IN EFI_LBA Lba,
3787 IN UINTN NumberOfBlocks,
3788 IN EFI_BLOCK_IO2_TOKEN *Token
3789 )
3790 {
3791 UINTN BlocksRemaining;
3792 UINT8 *PtrBuffer;
3793 UINT32 BlockSize;
3794 UINT32 ByteCount;
3795 UINT32 MaxBlock;
3796 UINT32 SectorCount;
3797 UINT64 Timeout;
3798 SCSI_BLKIO2_REQUEST *BlkIo2Req;
3799 EFI_STATUS Status;
3800 EFI_TPL OldTpl;
3801
3802 if ((Token == NULL) || (Token->Event == NULL)) {
3803 return EFI_INVALID_PARAMETER;
3804 }
3805
3806 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
3807 if (BlkIo2Req == NULL) {
3808 return EFI_OUT_OF_RESOURCES;
3809 }
3810
3811 BlkIo2Req->Token = Token;
3812
3813 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3814 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
3815 gBS->RestoreTPL (OldTpl);
3816
3817 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
3818
3819 Status = EFI_SUCCESS;
3820
3821 BlocksRemaining = NumberOfBlocks;
3822 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
3823
3824 //
3825 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3826 // Command
3827 //
3828 if (!ScsiDiskDevice->Cdb16Byte) {
3829 MaxBlock = 0xFFFF;
3830 } else {
3831 MaxBlock = 0xFFFFFFFF;
3832 }
3833
3834 PtrBuffer = Buffer;
3835
3836 while (BlocksRemaining > 0) {
3837 if (BlocksRemaining <= MaxBlock) {
3838 if (!ScsiDiskDevice->Cdb16Byte) {
3839 SectorCount = (UINT16)BlocksRemaining;
3840 } else {
3841 SectorCount = (UINT32)BlocksRemaining;
3842 }
3843 } else {
3844 SectorCount = MaxBlock;
3845 }
3846
3847 ByteCount = SectorCount * BlockSize;
3848 //
3849 // |------------------------|-----------------|------------------|-----------------|
3850 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3851 // |------------------------|-----------------|------------------|-----------------|
3852 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3853 // |------------------------|-----------------|------------------|-----------------|
3854 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3855 // |------------------------|-----------------|------------------|-----------------|
3856 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3857 // |------------------------|-----------------|------------------|-----------------|
3858 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3859 // |------------------------|-----------------|------------------|-----------------|
3860 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3861 // |------------------------|-----------------|------------------|-----------------|
3862 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3863 // |------------------------|-----------------|------------------|-----------------|
3864 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3865 // |------------------------|-----------------|------------------|-----------------|
3866 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3867 // |------------------------|-----------------|------------------|-----------------|
3868 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3869 // |------------------------|-----------------|------------------|-----------------|
3870 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3871 // |------------------------|-----------------|------------------|-----------------|
3872 //
3873 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3874 // we have to use the lowest transfer rate to calculate the possible
3875 // maximum timeout value for each operation.
3876 // From the above table, we could know 2.1Mbytes per second is lowest one.
3877 // The timeout value is rounded up to nearest integer and here an additional
3878 // 30s is added to follow ATA spec in which it mentioned that the device
3879 // may take up to 30s to respond commands in the Standby/Idle mode.
3880 //
3881 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3882
3883 if (!ScsiDiskDevice->Cdb16Byte) {
3884 Status = ScsiDiskAsyncRead10 (
3885 ScsiDiskDevice,
3886 Timeout,
3887 0,
3888 PtrBuffer,
3889 ByteCount,
3890 (UINT32)Lba,
3891 SectorCount,
3892 BlkIo2Req,
3893 Token
3894 );
3895 } else {
3896 Status = ScsiDiskAsyncRead16 (
3897 ScsiDiskDevice,
3898 Timeout,
3899 0,
3900 PtrBuffer,
3901 ByteCount,
3902 Lba,
3903 SectorCount,
3904 BlkIo2Req,
3905 Token
3906 );
3907 }
3908
3909 if (EFI_ERROR (Status)) {
3910 //
3911 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3912 // length of a SCSI I/O command is too large.
3913 // In this case, we retry sending the SCSI command with a data length
3914 // half of its previous value.
3915 //
3916 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
3917 if ((MaxBlock > 1) && (SectorCount > 1)) {
3918 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
3919 continue;
3920 }
3921 }
3922
3923 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3924 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3925 //
3926 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3927 // SCSI sub-task running. Otherwise, it will be freed in the callback
3928 // function ScsiDiskNotify().
3929 //
3930 RemoveEntryList (&BlkIo2Req->Link);
3931 FreePool (BlkIo2Req);
3932 BlkIo2Req = NULL;
3933 gBS->RestoreTPL (OldTpl);
3934
3935 //
3936 // It is safe to return error status to the caller, since there is no
3937 // previous SCSI sub-task executing.
3938 //
3939 Status = EFI_DEVICE_ERROR;
3940 goto Done;
3941 } else {
3942 gBS->RestoreTPL (OldTpl);
3943
3944 //
3945 // There are previous SCSI commands still running, EFI_SUCCESS should
3946 // be returned to make sure that the caller does not free resources
3947 // still using by these SCSI commands.
3948 //
3949 Status = EFI_SUCCESS;
3950 goto Done;
3951 }
3952 }
3953
3954 //
3955 // Sectors submitted for transfer
3956 //
3957 SectorCount = ByteCount / BlockSize;
3958
3959 Lba += SectorCount;
3960 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3961 BlocksRemaining -= SectorCount;
3962 }
3963
3964 Status = EFI_SUCCESS;
3965
3966 Done:
3967 if (BlkIo2Req != NULL) {
3968 BlkIo2Req->LastScsiRW = TRUE;
3969
3970 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3971 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3972 RemoveEntryList (&BlkIo2Req->Link);
3973 FreePool (BlkIo2Req);
3974 BlkIo2Req = NULL;
3975
3976 gBS->SignalEvent (Token->Event);
3977 }
3978
3979 gBS->RestoreTPL (OldTpl);
3980 }
3981
3982 return Status;
3983 }
3984
3985 /**
3986 Asynchronously write sector to SCSI Disk.
3987
3988 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3989 @param Buffer The buffer of data to be written into SCSI Disk.
3990 @param Lba Logic block address.
3991 @param NumberOfBlocks The number of blocks to read.
3992 @param Token A pointer to the token associated with the
3993 non-blocking read request.
3994
3995 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
3996 @retval EFI_DEVICE_ERROR Indicates a device error.
3997 @retval EFI_SUCCESS Operation is successful.
3998
3999 **/
4000 EFI_STATUS
4001 ScsiDiskAsyncWriteSectors (
4002 IN SCSI_DISK_DEV *ScsiDiskDevice,
4003 IN VOID *Buffer,
4004 IN EFI_LBA Lba,
4005 IN UINTN NumberOfBlocks,
4006 IN EFI_BLOCK_IO2_TOKEN *Token
4007 )
4008 {
4009 UINTN BlocksRemaining;
4010 UINT8 *PtrBuffer;
4011 UINT32 BlockSize;
4012 UINT32 ByteCount;
4013 UINT32 MaxBlock;
4014 UINT32 SectorCount;
4015 UINT64 Timeout;
4016 SCSI_BLKIO2_REQUEST *BlkIo2Req;
4017 EFI_STATUS Status;
4018 EFI_TPL OldTpl;
4019
4020 if ((Token == NULL) || (Token->Event == NULL)) {
4021 return EFI_INVALID_PARAMETER;
4022 }
4023
4024 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
4025 if (BlkIo2Req == NULL) {
4026 return EFI_OUT_OF_RESOURCES;
4027 }
4028
4029 BlkIo2Req->Token = Token;
4030
4031 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4032 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
4033 gBS->RestoreTPL (OldTpl);
4034
4035 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
4036
4037 Status = EFI_SUCCESS;
4038
4039 BlocksRemaining = NumberOfBlocks;
4040 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
4041
4042 //
4043 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
4044 // Command
4045 //
4046 if (!ScsiDiskDevice->Cdb16Byte) {
4047 MaxBlock = 0xFFFF;
4048 } else {
4049 MaxBlock = 0xFFFFFFFF;
4050 }
4051
4052 PtrBuffer = Buffer;
4053
4054 while (BlocksRemaining > 0) {
4055 if (BlocksRemaining <= MaxBlock) {
4056 if (!ScsiDiskDevice->Cdb16Byte) {
4057 SectorCount = (UINT16)BlocksRemaining;
4058 } else {
4059 SectorCount = (UINT32)BlocksRemaining;
4060 }
4061 } else {
4062 SectorCount = MaxBlock;
4063 }
4064
4065 ByteCount = SectorCount * BlockSize;
4066 //
4067 // |------------------------|-----------------|------------------|-----------------|
4068 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
4069 // |------------------------|-----------------|------------------|-----------------|
4070 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
4071 // |------------------------|-----------------|------------------|-----------------|
4072 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
4073 // |------------------------|-----------------|------------------|-----------------|
4074 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
4075 // |------------------------|-----------------|------------------|-----------------|
4076 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
4077 // |------------------------|-----------------|------------------|-----------------|
4078 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
4079 // |------------------------|-----------------|------------------|-----------------|
4080 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
4081 // |------------------------|-----------------|------------------|-----------------|
4082 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
4083 // |------------------------|-----------------|------------------|-----------------|
4084 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
4085 // |------------------------|-----------------|------------------|-----------------|
4086 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
4087 // |------------------------|-----------------|------------------|-----------------|
4088 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
4089 // |------------------------|-----------------|------------------|-----------------|
4090 //
4091 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
4092 // we have to use the lowest transfer rate to calculate the possible
4093 // maximum timeout value for each operation.
4094 // From the above table, we could know 2.1Mbytes per second is lowest one.
4095 // The timeout value is rounded up to nearest integer and here an additional
4096 // 30s is added to follow ATA spec in which it mentioned that the device
4097 // may take up to 30s to respond commands in the Standby/Idle mode.
4098 //
4099 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
4100
4101 if (!ScsiDiskDevice->Cdb16Byte) {
4102 Status = ScsiDiskAsyncWrite10 (
4103 ScsiDiskDevice,
4104 Timeout,
4105 0,
4106 PtrBuffer,
4107 ByteCount,
4108 (UINT32)Lba,
4109 SectorCount,
4110 BlkIo2Req,
4111 Token
4112 );
4113 } else {
4114 Status = ScsiDiskAsyncWrite16 (
4115 ScsiDiskDevice,
4116 Timeout,
4117 0,
4118 PtrBuffer,
4119 ByteCount,
4120 Lba,
4121 SectorCount,
4122 BlkIo2Req,
4123 Token
4124 );
4125 }
4126
4127 if (EFI_ERROR (Status)) {
4128 //
4129 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
4130 // length of a SCSI I/O command is too large.
4131 // In this case, we retry sending the SCSI command with a data length
4132 // half of its previous value.
4133 //
4134 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
4135 if ((MaxBlock > 1) && (SectorCount > 1)) {
4136 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
4137 continue;
4138 }
4139 }
4140
4141 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4142 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
4143 //
4144 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
4145 // SCSI sub-task running. Otherwise, it will be freed in the callback
4146 // function ScsiDiskNotify().
4147 //
4148 RemoveEntryList (&BlkIo2Req->Link);
4149 FreePool (BlkIo2Req);
4150 BlkIo2Req = NULL;
4151 gBS->RestoreTPL (OldTpl);
4152
4153 //
4154 // It is safe to return error status to the caller, since there is no
4155 // previous SCSI sub-task executing.
4156 //
4157 Status = EFI_DEVICE_ERROR;
4158 goto Done;
4159 } else {
4160 gBS->RestoreTPL (OldTpl);
4161
4162 //
4163 // There are previous SCSI commands still running, EFI_SUCCESS should
4164 // be returned to make sure that the caller does not free resources
4165 // still using by these SCSI commands.
4166 //
4167 Status = EFI_SUCCESS;
4168 goto Done;
4169 }
4170 }
4171
4172 //
4173 // Sectors submitted for transfer
4174 //
4175 SectorCount = ByteCount / BlockSize;
4176
4177 Lba += SectorCount;
4178 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
4179 BlocksRemaining -= SectorCount;
4180 }
4181
4182 Status = EFI_SUCCESS;
4183
4184 Done:
4185 if (BlkIo2Req != NULL) {
4186 BlkIo2Req->LastScsiRW = TRUE;
4187
4188 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4189 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
4190 RemoveEntryList (&BlkIo2Req->Link);
4191 FreePool (BlkIo2Req);
4192 BlkIo2Req = NULL;
4193
4194 gBS->SignalEvent (Token->Event);
4195 }
4196
4197 gBS->RestoreTPL (OldTpl);
4198 }
4199
4200 return Status;
4201 }
4202
4203 /**
4204 Submit Read(10) command.
4205
4206 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4207 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4208 @param Timeout The time to complete the command
4209 @param DataBuffer The buffer to fill with the read out data
4210 @param DataLength The length of buffer
4211 @param StartLba The start logic block address
4212 @param SectorCount The number of blocks to read
4213
4214 @return EFI_STATUS is returned by calling ScsiRead10Command().
4215 **/
4216 EFI_STATUS
4217 ScsiDiskRead10 (
4218 IN SCSI_DISK_DEV *ScsiDiskDevice,
4219 OUT BOOLEAN *NeedRetry,
4220 IN UINT64 Timeout,
4221 OUT UINT8 *DataBuffer,
4222 IN OUT UINT32 *DataLength,
4223 IN UINT32 StartLba,
4224 IN UINT32 SectorCount
4225 )
4226 {
4227 UINT8 SenseDataLength;
4228 EFI_STATUS Status;
4229 EFI_STATUS ReturnStatus;
4230 UINT8 HostAdapterStatus;
4231 UINT8 TargetStatus;
4232 UINTN Action;
4233
4234 //
4235 // Implement a backoff algorithm to resolve some compatibility issues that
4236 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4237 // big data in a single operation.
4238 // This algorithm will at first try to execute original request. If the request fails
4239 // with media error sense data or else, it will reduce the transfer length to half and
4240 // try again till the operation succeeds or fails with one sector transfer length.
4241 //
4242 BackOff:
4243 *NeedRetry = FALSE;
4244 Action = ACTION_NO_ACTION;
4245 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4246 ReturnStatus = ScsiRead10Command (
4247 ScsiDiskDevice->ScsiIo,
4248 Timeout,
4249 ScsiDiskDevice->SenseData,
4250 &SenseDataLength,
4251 &HostAdapterStatus,
4252 &TargetStatus,
4253 DataBuffer,
4254 DataLength,
4255 StartLba,
4256 SectorCount
4257 );
4258
4259 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4260 *NeedRetry = TRUE;
4261 return EFI_DEVICE_ERROR;
4262 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4263 *NeedRetry = FALSE;
4264 return ReturnStatus;
4265 }
4266
4267 //
4268 // go ahead to check HostAdapterStatus and TargetStatus
4269 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4270 //
4271 Status = CheckHostAdapterStatus (HostAdapterStatus);
4272 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4273 *NeedRetry = TRUE;
4274 return EFI_DEVICE_ERROR;
4275 } else if (Status == EFI_DEVICE_ERROR) {
4276 //
4277 // reset the scsi channel
4278 //
4279 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4280 *NeedRetry = FALSE;
4281 return EFI_DEVICE_ERROR;
4282 }
4283
4284 Status = CheckTargetStatus (TargetStatus);
4285 if (Status == EFI_NOT_READY) {
4286 //
4287 // reset the scsi device
4288 //
4289 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4290 *NeedRetry = TRUE;
4291 return EFI_DEVICE_ERROR;
4292 } else if (Status == EFI_DEVICE_ERROR) {
4293 *NeedRetry = FALSE;
4294 return EFI_DEVICE_ERROR;
4295 }
4296
4297 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4298 DEBUG ((DEBUG_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
4299 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4300 if (Action == ACTION_RETRY_COMMAND_LATER) {
4301 *NeedRetry = TRUE;
4302 return EFI_DEVICE_ERROR;
4303 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4304 if (SectorCount <= 1) {
4305 //
4306 // Jump out if the operation still fails with one sector transfer length.
4307 //
4308 *NeedRetry = FALSE;
4309 return EFI_DEVICE_ERROR;
4310 }
4311
4312 //
4313 // Try again with half length if the sense data shows we need to retry.
4314 //
4315 SectorCount >>= 1;
4316 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4317 goto BackOff;
4318 } else {
4319 *NeedRetry = FALSE;
4320 return EFI_DEVICE_ERROR;
4321 }
4322 }
4323
4324 return ReturnStatus;
4325 }
4326
4327 /**
4328 Submit Write(10) Command.
4329
4330 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4331 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4332 @param Timeout The time to complete the command
4333 @param DataBuffer The buffer to fill with the read out data
4334 @param DataLength The length of buffer
4335 @param StartLba The start logic block address
4336 @param SectorCount The number of blocks to write
4337
4338 @return EFI_STATUS is returned by calling ScsiWrite10Command().
4339
4340 **/
4341 EFI_STATUS
4342 ScsiDiskWrite10 (
4343 IN SCSI_DISK_DEV *ScsiDiskDevice,
4344 OUT BOOLEAN *NeedRetry,
4345 IN UINT64 Timeout,
4346 IN UINT8 *DataBuffer,
4347 IN OUT UINT32 *DataLength,
4348 IN UINT32 StartLba,
4349 IN UINT32 SectorCount
4350 )
4351 {
4352 EFI_STATUS Status;
4353 EFI_STATUS ReturnStatus;
4354 UINT8 SenseDataLength;
4355 UINT8 HostAdapterStatus;
4356 UINT8 TargetStatus;
4357 UINTN Action;
4358
4359 //
4360 // Implement a backoff algorithm to resolve some compatibility issues that
4361 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4362 // big data in a single operation.
4363 // This algorithm will at first try to execute original request. If the request fails
4364 // with media error sense data or else, it will reduce the transfer length to half and
4365 // try again till the operation succeeds or fails with one sector transfer length.
4366 //
4367 BackOff:
4368 *NeedRetry = FALSE;
4369 Action = ACTION_NO_ACTION;
4370 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4371 ReturnStatus = ScsiWrite10Command (
4372 ScsiDiskDevice->ScsiIo,
4373 Timeout,
4374 ScsiDiskDevice->SenseData,
4375 &SenseDataLength,
4376 &HostAdapterStatus,
4377 &TargetStatus,
4378 DataBuffer,
4379 DataLength,
4380 StartLba,
4381 SectorCount
4382 );
4383 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4384 *NeedRetry = TRUE;
4385 return EFI_DEVICE_ERROR;
4386 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4387 *NeedRetry = FALSE;
4388 return ReturnStatus;
4389 }
4390
4391 //
4392 // go ahead to check HostAdapterStatus and TargetStatus
4393 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4394 //
4395 Status = CheckHostAdapterStatus (HostAdapterStatus);
4396 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4397 *NeedRetry = TRUE;
4398 return EFI_DEVICE_ERROR;
4399 } else if (Status == EFI_DEVICE_ERROR) {
4400 //
4401 // reset the scsi channel
4402 //
4403 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4404 *NeedRetry = FALSE;
4405 return EFI_DEVICE_ERROR;
4406 }
4407
4408 Status = CheckTargetStatus (TargetStatus);
4409 if (Status == EFI_NOT_READY) {
4410 //
4411 // reset the scsi device
4412 //
4413 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4414 *NeedRetry = TRUE;
4415 return EFI_DEVICE_ERROR;
4416 } else if (Status == EFI_DEVICE_ERROR) {
4417 *NeedRetry = FALSE;
4418 return EFI_DEVICE_ERROR;
4419 }
4420
4421 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4422 DEBUG ((DEBUG_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
4423 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4424 if (Action == ACTION_RETRY_COMMAND_LATER) {
4425 *NeedRetry = TRUE;
4426 return EFI_DEVICE_ERROR;
4427 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4428 if (SectorCount <= 1) {
4429 //
4430 // Jump out if the operation still fails with one sector transfer length.
4431 //
4432 *NeedRetry = FALSE;
4433 return EFI_DEVICE_ERROR;
4434 }
4435
4436 //
4437 // Try again with half length if the sense data shows we need to retry.
4438 //
4439 SectorCount >>= 1;
4440 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4441 goto BackOff;
4442 } else {
4443 *NeedRetry = FALSE;
4444 return EFI_DEVICE_ERROR;
4445 }
4446 }
4447
4448 return ReturnStatus;
4449 }
4450
4451 /**
4452 Submit Read(16) command.
4453
4454 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4455 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4456 @param Timeout The time to complete the command
4457 @param DataBuffer The buffer to fill with the read out data
4458 @param DataLength The length of buffer
4459 @param StartLba The start logic block address
4460 @param SectorCount The number of blocks to read
4461
4462 @return EFI_STATUS is returned by calling ScsiRead16Command().
4463 **/
4464 EFI_STATUS
4465 ScsiDiskRead16 (
4466 IN SCSI_DISK_DEV *ScsiDiskDevice,
4467 OUT BOOLEAN *NeedRetry,
4468 IN UINT64 Timeout,
4469 OUT UINT8 *DataBuffer,
4470 IN OUT UINT32 *DataLength,
4471 IN UINT64 StartLba,
4472 IN UINT32 SectorCount
4473 )
4474 {
4475 UINT8 SenseDataLength;
4476 EFI_STATUS Status;
4477 EFI_STATUS ReturnStatus;
4478 UINT8 HostAdapterStatus;
4479 UINT8 TargetStatus;
4480 UINTN Action;
4481
4482 //
4483 // Implement a backoff algorithm to resolve some compatibility issues that
4484 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4485 // big data in a single operation.
4486 // This algorithm will at first try to execute original request. If the request fails
4487 // with media error sense data or else, it will reduce the transfer length to half and
4488 // try again till the operation succeeds or fails with one sector transfer length.
4489 //
4490 BackOff:
4491 *NeedRetry = FALSE;
4492 Action = ACTION_NO_ACTION;
4493 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4494 ReturnStatus = ScsiRead16Command (
4495 ScsiDiskDevice->ScsiIo,
4496 Timeout,
4497 ScsiDiskDevice->SenseData,
4498 &SenseDataLength,
4499 &HostAdapterStatus,
4500 &TargetStatus,
4501 DataBuffer,
4502 DataLength,
4503 StartLba,
4504 SectorCount
4505 );
4506 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4507 *NeedRetry = TRUE;
4508 return EFI_DEVICE_ERROR;
4509 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4510 *NeedRetry = FALSE;
4511 return ReturnStatus;
4512 }
4513
4514 //
4515 // go ahead to check HostAdapterStatus and TargetStatus
4516 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4517 //
4518 Status = CheckHostAdapterStatus (HostAdapterStatus);
4519 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4520 *NeedRetry = TRUE;
4521 return EFI_DEVICE_ERROR;
4522 } else if (Status == EFI_DEVICE_ERROR) {
4523 //
4524 // reset the scsi channel
4525 //
4526 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4527 *NeedRetry = FALSE;
4528 return EFI_DEVICE_ERROR;
4529 }
4530
4531 Status = CheckTargetStatus (TargetStatus);
4532 if (Status == EFI_NOT_READY) {
4533 //
4534 // reset the scsi device
4535 //
4536 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4537 *NeedRetry = TRUE;
4538 return EFI_DEVICE_ERROR;
4539 } else if (Status == EFI_DEVICE_ERROR) {
4540 *NeedRetry = FALSE;
4541 return EFI_DEVICE_ERROR;
4542 }
4543
4544 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4545 DEBUG ((DEBUG_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
4546 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4547 if (Action == ACTION_RETRY_COMMAND_LATER) {
4548 *NeedRetry = TRUE;
4549 return EFI_DEVICE_ERROR;
4550 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4551 if (SectorCount <= 1) {
4552 //
4553 // Jump out if the operation still fails with one sector transfer length.
4554 //
4555 *NeedRetry = FALSE;
4556 return EFI_DEVICE_ERROR;
4557 }
4558
4559 //
4560 // Try again with half length if the sense data shows we need to retry.
4561 //
4562 SectorCount >>= 1;
4563 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4564 goto BackOff;
4565 } else {
4566 *NeedRetry = FALSE;
4567 return EFI_DEVICE_ERROR;
4568 }
4569 }
4570
4571 return ReturnStatus;
4572 }
4573
4574 /**
4575 Submit Write(16) Command.
4576
4577 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4578 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4579 @param Timeout The time to complete the command
4580 @param DataBuffer The buffer to fill with the read out data
4581 @param DataLength The length of buffer
4582 @param StartLba The start logic block address
4583 @param SectorCount The number of blocks to write
4584
4585 @return EFI_STATUS is returned by calling ScsiWrite16Command().
4586
4587 **/
4588 EFI_STATUS
4589 ScsiDiskWrite16 (
4590 IN SCSI_DISK_DEV *ScsiDiskDevice,
4591 OUT BOOLEAN *NeedRetry,
4592 IN UINT64 Timeout,
4593 IN UINT8 *DataBuffer,
4594 IN OUT UINT32 *DataLength,
4595 IN UINT64 StartLba,
4596 IN UINT32 SectorCount
4597 )
4598 {
4599 EFI_STATUS Status;
4600 EFI_STATUS ReturnStatus;
4601 UINT8 SenseDataLength;
4602 UINT8 HostAdapterStatus;
4603 UINT8 TargetStatus;
4604 UINTN Action;
4605
4606 //
4607 // Implement a backoff algorithm to resolve some compatibility issues that
4608 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4609 // big data in a single operation.
4610 // This algorithm will at first try to execute original request. If the request fails
4611 // with media error sense data or else, it will reduce the transfer length to half and
4612 // try again till the operation succeeds or fails with one sector transfer length.
4613 //
4614 BackOff:
4615 *NeedRetry = FALSE;
4616 Action = ACTION_NO_ACTION;
4617 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4618 ReturnStatus = ScsiWrite16Command (
4619 ScsiDiskDevice->ScsiIo,
4620 Timeout,
4621 ScsiDiskDevice->SenseData,
4622 &SenseDataLength,
4623 &HostAdapterStatus,
4624 &TargetStatus,
4625 DataBuffer,
4626 DataLength,
4627 StartLba,
4628 SectorCount
4629 );
4630 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
4631 *NeedRetry = TRUE;
4632 return EFI_DEVICE_ERROR;
4633 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4634 *NeedRetry = FALSE;
4635 return ReturnStatus;
4636 }
4637
4638 //
4639 // go ahead to check HostAdapterStatus and TargetStatus
4640 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4641 //
4642 Status = CheckHostAdapterStatus (HostAdapterStatus);
4643 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4644 *NeedRetry = TRUE;
4645 return EFI_DEVICE_ERROR;
4646 } else if (Status == EFI_DEVICE_ERROR) {
4647 //
4648 // reset the scsi channel
4649 //
4650 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4651 *NeedRetry = FALSE;
4652 return EFI_DEVICE_ERROR;
4653 }
4654
4655 Status = CheckTargetStatus (TargetStatus);
4656 if (Status == EFI_NOT_READY) {
4657 //
4658 // reset the scsi device
4659 //
4660 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4661 *NeedRetry = TRUE;
4662 return EFI_DEVICE_ERROR;
4663 } else if (Status == EFI_DEVICE_ERROR) {
4664 *NeedRetry = FALSE;
4665 return EFI_DEVICE_ERROR;
4666 }
4667
4668 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4669 DEBUG ((DEBUG_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
4670 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4671 if (Action == ACTION_RETRY_COMMAND_LATER) {
4672 *NeedRetry = TRUE;
4673 return EFI_DEVICE_ERROR;
4674 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4675 if (SectorCount <= 1) {
4676 //
4677 // Jump out if the operation still fails with one sector transfer length.
4678 //
4679 *NeedRetry = FALSE;
4680 return EFI_DEVICE_ERROR;
4681 }
4682
4683 //
4684 // Try again with half length if the sense data shows we need to retry.
4685 //
4686 SectorCount >>= 1;
4687 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4688 goto BackOff;
4689 } else {
4690 *NeedRetry = FALSE;
4691 return EFI_DEVICE_ERROR;
4692 }
4693 }
4694
4695 return ReturnStatus;
4696 }
4697
4698 /**
4699 Internal helper notify function in which determine whether retry of a SCSI
4700 Read/Write command is needed and signal the event passed from Block I/O(2) if
4701 the SCSI I/O operation completes.
4702
4703 @param Event The instance of EFI_EVENT.
4704 @param Context The parameter passed in.
4705
4706 **/
4707 VOID
4708 EFIAPI
4709 ScsiDiskNotify (
4710 IN EFI_EVENT Event,
4711 IN VOID *Context
4712 )
4713 {
4714 EFI_STATUS Status;
4715 SCSI_ASYNC_RW_REQUEST *Request;
4716 SCSI_DISK_DEV *ScsiDiskDevice;
4717 EFI_BLOCK_IO2_TOKEN *Token;
4718 UINTN Action;
4719 UINT32 OldDataLength;
4720 UINT32 OldSectorCount;
4721 UINT8 MaxRetry;
4722
4723 gBS->CloseEvent (Event);
4724
4725 Request = (SCSI_ASYNC_RW_REQUEST *)Context;
4726 ScsiDiskDevice = Request->ScsiDiskDevice;
4727 Token = Request->BlkIo2Req->Token;
4728 OldDataLength = Request->DataLength;
4729 OldSectorCount = Request->SectorCount;
4730 MaxRetry = 2;
4731
4732 //
4733 // If previous sub-tasks already fails, no need to process this sub-task.
4734 //
4735 if (Token->TransactionStatus != EFI_SUCCESS) {
4736 goto Exit;
4737 }
4738
4739 //
4740 // Check HostAdapterStatus and TargetStatus
4741 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4742 //
4743 Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
4744 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4745 if (++Request->TimesRetry > MaxRetry) {
4746 Token->TransactionStatus = EFI_DEVICE_ERROR;
4747 goto Exit;
4748 } else {
4749 goto Retry;
4750 }
4751 } else if (Status == EFI_DEVICE_ERROR) {
4752 //
4753 // reset the scsi channel
4754 //
4755 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4756 Token->TransactionStatus = EFI_DEVICE_ERROR;
4757 goto Exit;
4758 }
4759
4760 Status = CheckTargetStatus (Request->TargetStatus);
4761 if (Status == EFI_NOT_READY) {
4762 //
4763 // reset the scsi device
4764 //
4765 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4766 if (++Request->TimesRetry > MaxRetry) {
4767 Token->TransactionStatus = EFI_DEVICE_ERROR;
4768 goto Exit;
4769 } else {
4770 goto Retry;
4771 }
4772 } else if (Status == EFI_DEVICE_ERROR) {
4773 Token->TransactionStatus = EFI_DEVICE_ERROR;
4774 goto Exit;
4775 }
4776
4777 if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
4778 DEBUG ((DEBUG_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
4779
4780 DetectMediaParsingSenseKeys (
4781 ScsiDiskDevice,
4782 Request->SenseData,
4783 Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
4784 &Action
4785 );
4786 if (Action == ACTION_RETRY_COMMAND_LATER) {
4787 if (++Request->TimesRetry > MaxRetry) {
4788 Token->TransactionStatus = EFI_DEVICE_ERROR;
4789 goto Exit;
4790 } else {
4791 goto Retry;
4792 }
4793 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4794 if (Request->SectorCount <= 1) {
4795 //
4796 // Jump out if the operation still fails with one sector transfer
4797 // length.
4798 //
4799 Token->TransactionStatus = EFI_DEVICE_ERROR;
4800 goto Exit;
4801 }
4802
4803 //
4804 // Try again with two half length request if the sense data shows we need
4805 // to retry.
4806 //
4807 Request->SectorCount >>= 1;
4808 Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4809 Request->TimesRetry = 0;
4810
4811 goto Retry;
4812 } else {
4813 Token->TransactionStatus = EFI_DEVICE_ERROR;
4814 goto Exit;
4815 }
4816 }
4817
4818 //
4819 // This sub-task succeeds, no need to retry.
4820 //
4821 goto Exit;
4822
4823 Retry:
4824 if (Request->InBuffer != NULL) {
4825 //
4826 // SCSI read command
4827 //
4828 if (!ScsiDiskDevice->Cdb16Byte) {
4829 Status = ScsiDiskAsyncRead10 (
4830 ScsiDiskDevice,
4831 Request->Timeout,
4832 Request->TimesRetry,
4833 Request->InBuffer,
4834 Request->DataLength,
4835 (UINT32)Request->StartLba,
4836 Request->SectorCount,
4837 Request->BlkIo2Req,
4838 Token
4839 );
4840 } else {
4841 Status = ScsiDiskAsyncRead16 (
4842 ScsiDiskDevice,
4843 Request->Timeout,
4844 Request->TimesRetry,
4845 Request->InBuffer,
4846 Request->DataLength,
4847 Request->StartLba,
4848 Request->SectorCount,
4849 Request->BlkIo2Req,
4850 Token
4851 );
4852 }
4853
4854 if (EFI_ERROR (Status)) {
4855 Token->TransactionStatus = EFI_DEVICE_ERROR;
4856 goto Exit;
4857 } else if (OldSectorCount != Request->SectorCount) {
4858 //
4859 // Original sub-task will be split into two new sub-tasks with smaller
4860 // DataLength
4861 //
4862 if (!ScsiDiskDevice->Cdb16Byte) {
4863 Status = ScsiDiskAsyncRead10 (
4864 ScsiDiskDevice,
4865 Request->Timeout,
4866 0,
4867 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4868 OldDataLength - Request->DataLength,
4869 (UINT32)Request->StartLba + Request->SectorCount,
4870 OldSectorCount - Request->SectorCount,
4871 Request->BlkIo2Req,
4872 Token
4873 );
4874 } else {
4875 Status = ScsiDiskAsyncRead16 (
4876 ScsiDiskDevice,
4877 Request->Timeout,
4878 0,
4879 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4880 OldDataLength - Request->DataLength,
4881 Request->StartLba + Request->SectorCount,
4882 OldSectorCount - Request->SectorCount,
4883 Request->BlkIo2Req,
4884 Token
4885 );
4886 }
4887
4888 if (EFI_ERROR (Status)) {
4889 Token->TransactionStatus = EFI_DEVICE_ERROR;
4890 goto Exit;
4891 }
4892 }
4893 } else {
4894 //
4895 // SCSI write command
4896 //
4897 if (!ScsiDiskDevice->Cdb16Byte) {
4898 Status = ScsiDiskAsyncWrite10 (
4899 ScsiDiskDevice,
4900 Request->Timeout,
4901 Request->TimesRetry,
4902 Request->OutBuffer,
4903 Request->DataLength,
4904 (UINT32)Request->StartLba,
4905 Request->SectorCount,
4906 Request->BlkIo2Req,
4907 Token
4908 );
4909 } else {
4910 Status = ScsiDiskAsyncWrite16 (
4911 ScsiDiskDevice,
4912 Request->Timeout,
4913 Request->TimesRetry,
4914 Request->OutBuffer,
4915 Request->DataLength,
4916 Request->StartLba,
4917 Request->SectorCount,
4918 Request->BlkIo2Req,
4919 Token
4920 );
4921 }
4922
4923 if (EFI_ERROR (Status)) {
4924 Token->TransactionStatus = EFI_DEVICE_ERROR;
4925 goto Exit;
4926 } else if (OldSectorCount != Request->SectorCount) {
4927 //
4928 // Original sub-task will be split into two new sub-tasks with smaller
4929 // DataLength
4930 //
4931 if (!ScsiDiskDevice->Cdb16Byte) {
4932 Status = ScsiDiskAsyncWrite10 (
4933 ScsiDiskDevice,
4934 Request->Timeout,
4935 0,
4936 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4937 OldDataLength - Request->DataLength,
4938 (UINT32)Request->StartLba + Request->SectorCount,
4939 OldSectorCount - Request->SectorCount,
4940 Request->BlkIo2Req,
4941 Token
4942 );
4943 } else {
4944 Status = ScsiDiskAsyncWrite16 (
4945 ScsiDiskDevice,
4946 Request->Timeout,
4947 0,
4948 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4949 OldDataLength - Request->DataLength,
4950 Request->StartLba + Request->SectorCount,
4951 OldSectorCount - Request->SectorCount,
4952 Request->BlkIo2Req,
4953 Token
4954 );
4955 }
4956
4957 if (EFI_ERROR (Status)) {
4958 Token->TransactionStatus = EFI_DEVICE_ERROR;
4959 goto Exit;
4960 }
4961 }
4962 }
4963
4964 Exit:
4965 RemoveEntryList (&Request->Link);
4966 if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
4967 (Request->BlkIo2Req->LastScsiRW))
4968 {
4969 //
4970 // The last SCSI R/W command of a BlockIo2 request completes
4971 //
4972 RemoveEntryList (&Request->BlkIo2Req->Link);
4973 FreePool (Request->BlkIo2Req); // Should be freed only once
4974 gBS->SignalEvent (Token->Event);
4975 }
4976
4977 FreePool (Request->SenseData);
4978 FreePool (Request);
4979 }
4980
4981 /**
4982 Submit Async Read(10) command.
4983
4984 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4985 @param Timeout The time to complete the command.
4986 @param TimesRetry The number of times the command has been retried.
4987 @param DataBuffer The buffer to fill with the read out data.
4988 @param DataLength The length of buffer.
4989 @param StartLba The start logic block address.
4990 @param SectorCount The number of blocks to read.
4991 @param BlkIo2Req The upstream BlockIo2 request.
4992 @param Token The pointer to the token associated with the
4993 non-blocking read request.
4994
4995 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4996 lack of resources.
4997 @return others Status returned by calling
4998 ScsiRead10CommandEx().
4999
5000 **/
5001 EFI_STATUS
5002 ScsiDiskAsyncRead10 (
5003 IN SCSI_DISK_DEV *ScsiDiskDevice,
5004 IN UINT64 Timeout,
5005 IN UINT8 TimesRetry,
5006 OUT UINT8 *DataBuffer,
5007 IN UINT32 DataLength,
5008 IN UINT32 StartLba,
5009 IN UINT32 SectorCount,
5010 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5011 IN EFI_BLOCK_IO2_TOKEN *Token
5012 )
5013 {
5014 EFI_STATUS Status;
5015 SCSI_ASYNC_RW_REQUEST *Request;
5016 EFI_EVENT AsyncIoEvent;
5017 EFI_TPL OldTpl;
5018
5019 AsyncIoEvent = NULL;
5020
5021 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5022 if (Request == NULL) {
5023 return EFI_OUT_OF_RESOURCES;
5024 }
5025
5026 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5027 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5028 gBS->RestoreTPL (OldTpl);
5029
5030 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5031 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5032 if (Request->SenseData == NULL) {
5033 Status = EFI_OUT_OF_RESOURCES;
5034 goto ErrorExit;
5035 }
5036
5037 Request->ScsiDiskDevice = ScsiDiskDevice;
5038 Request->Timeout = Timeout;
5039 Request->TimesRetry = TimesRetry;
5040 Request->InBuffer = DataBuffer;
5041 Request->DataLength = DataLength;
5042 Request->StartLba = StartLba;
5043 Request->SectorCount = SectorCount;
5044 Request->BlkIo2Req = BlkIo2Req;
5045
5046 //
5047 // Create Event
5048 //
5049 Status = gBS->CreateEvent (
5050 EVT_NOTIFY_SIGNAL,
5051 TPL_NOTIFY,
5052 ScsiDiskNotify,
5053 Request,
5054 &AsyncIoEvent
5055 );
5056 if (EFI_ERROR (Status)) {
5057 goto ErrorExit;
5058 }
5059
5060 Status = ScsiRead10CommandEx (
5061 ScsiDiskDevice->ScsiIo,
5062 Request->Timeout,
5063 Request->SenseData,
5064 &Request->SenseDataLength,
5065 &Request->HostAdapterStatus,
5066 &Request->TargetStatus,
5067 Request->InBuffer,
5068 &Request->DataLength,
5069 (UINT32)Request->StartLba,
5070 Request->SectorCount,
5071 AsyncIoEvent
5072 );
5073 if (EFI_ERROR (Status)) {
5074 goto ErrorExit;
5075 }
5076
5077 return EFI_SUCCESS;
5078
5079 ErrorExit:
5080 if (AsyncIoEvent != NULL) {
5081 gBS->CloseEvent (AsyncIoEvent);
5082 }
5083
5084 if (Request != NULL) {
5085 if (Request->SenseData != NULL) {
5086 FreePool (Request->SenseData);
5087 }
5088
5089 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5090 RemoveEntryList (&Request->Link);
5091 gBS->RestoreTPL (OldTpl);
5092
5093 FreePool (Request);
5094 }
5095
5096 return Status;
5097 }
5098
5099 /**
5100 Submit Async Write(10) command.
5101
5102 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5103 @param Timeout The time to complete the command.
5104 @param TimesRetry The number of times the command has been retried.
5105 @param DataBuffer The buffer contains the data to write.
5106 @param DataLength The length of buffer.
5107 @param StartLba The start logic block address.
5108 @param SectorCount The number of blocks to write.
5109 @param BlkIo2Req The upstream BlockIo2 request.
5110 @param Token The pointer to the token associated with the
5111 non-blocking read request.
5112
5113 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5114 lack of resources.
5115 @return others Status returned by calling
5116 ScsiWrite10CommandEx().
5117
5118 **/
5119 EFI_STATUS
5120 ScsiDiskAsyncWrite10 (
5121 IN SCSI_DISK_DEV *ScsiDiskDevice,
5122 IN UINT64 Timeout,
5123 IN UINT8 TimesRetry,
5124 IN UINT8 *DataBuffer,
5125 IN UINT32 DataLength,
5126 IN UINT32 StartLba,
5127 IN UINT32 SectorCount,
5128 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5129 IN EFI_BLOCK_IO2_TOKEN *Token
5130 )
5131 {
5132 EFI_STATUS Status;
5133 SCSI_ASYNC_RW_REQUEST *Request;
5134 EFI_EVENT AsyncIoEvent;
5135 EFI_TPL OldTpl;
5136
5137 AsyncIoEvent = NULL;
5138
5139 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5140 if (Request == NULL) {
5141 return EFI_OUT_OF_RESOURCES;
5142 }
5143
5144 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5145 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5146 gBS->RestoreTPL (OldTpl);
5147
5148 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5149 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5150 if (Request->SenseData == NULL) {
5151 Status = EFI_OUT_OF_RESOURCES;
5152 goto ErrorExit;
5153 }
5154
5155 Request->ScsiDiskDevice = ScsiDiskDevice;
5156 Request->Timeout = Timeout;
5157 Request->TimesRetry = TimesRetry;
5158 Request->OutBuffer = DataBuffer;
5159 Request->DataLength = DataLength;
5160 Request->StartLba = StartLba;
5161 Request->SectorCount = SectorCount;
5162 Request->BlkIo2Req = BlkIo2Req;
5163
5164 //
5165 // Create Event
5166 //
5167 Status = gBS->CreateEvent (
5168 EVT_NOTIFY_SIGNAL,
5169 TPL_NOTIFY,
5170 ScsiDiskNotify,
5171 Request,
5172 &AsyncIoEvent
5173 );
5174 if (EFI_ERROR (Status)) {
5175 goto ErrorExit;
5176 }
5177
5178 Status = ScsiWrite10CommandEx (
5179 ScsiDiskDevice->ScsiIo,
5180 Request->Timeout,
5181 Request->SenseData,
5182 &Request->SenseDataLength,
5183 &Request->HostAdapterStatus,
5184 &Request->TargetStatus,
5185 Request->OutBuffer,
5186 &Request->DataLength,
5187 (UINT32)Request->StartLba,
5188 Request->SectorCount,
5189 AsyncIoEvent
5190 );
5191 if (EFI_ERROR (Status)) {
5192 goto ErrorExit;
5193 }
5194
5195 return EFI_SUCCESS;
5196
5197 ErrorExit:
5198 if (AsyncIoEvent != NULL) {
5199 gBS->CloseEvent (AsyncIoEvent);
5200 }
5201
5202 if (Request != NULL) {
5203 if (Request->SenseData != NULL) {
5204 FreePool (Request->SenseData);
5205 }
5206
5207 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5208 RemoveEntryList (&Request->Link);
5209 gBS->RestoreTPL (OldTpl);
5210
5211 FreePool (Request);
5212 }
5213
5214 return Status;
5215 }
5216
5217 /**
5218 Submit Async Read(16) command.
5219
5220 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5221 @param Timeout The time to complete the command.
5222 @param TimesRetry The number of times the command has been retried.
5223 @param DataBuffer The buffer to fill with the read out data.
5224 @param DataLength The length of buffer.
5225 @param StartLba The start logic block address.
5226 @param SectorCount The number of blocks to read.
5227 @param BlkIo2Req The upstream BlockIo2 request.
5228 @param Token The pointer to the token associated with the
5229 non-blocking read request.
5230
5231 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5232 lack of resources.
5233 @return others Status returned by calling
5234 ScsiRead16CommandEx().
5235
5236 **/
5237 EFI_STATUS
5238 ScsiDiskAsyncRead16 (
5239 IN SCSI_DISK_DEV *ScsiDiskDevice,
5240 IN UINT64 Timeout,
5241 IN UINT8 TimesRetry,
5242 OUT UINT8 *DataBuffer,
5243 IN UINT32 DataLength,
5244 IN UINT64 StartLba,
5245 IN UINT32 SectorCount,
5246 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5247 IN EFI_BLOCK_IO2_TOKEN *Token
5248 )
5249 {
5250 EFI_STATUS Status;
5251 SCSI_ASYNC_RW_REQUEST *Request;
5252 EFI_EVENT AsyncIoEvent;
5253 EFI_TPL OldTpl;
5254
5255 AsyncIoEvent = NULL;
5256
5257 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5258 if (Request == NULL) {
5259 return EFI_OUT_OF_RESOURCES;
5260 }
5261
5262 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5263 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5264 gBS->RestoreTPL (OldTpl);
5265
5266 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5267 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5268 if (Request->SenseData == NULL) {
5269 Status = EFI_OUT_OF_RESOURCES;
5270 goto ErrorExit;
5271 }
5272
5273 Request->ScsiDiskDevice = ScsiDiskDevice;
5274 Request->Timeout = Timeout;
5275 Request->TimesRetry = TimesRetry;
5276 Request->InBuffer = DataBuffer;
5277 Request->DataLength = DataLength;
5278 Request->StartLba = StartLba;
5279 Request->SectorCount = SectorCount;
5280 Request->BlkIo2Req = BlkIo2Req;
5281
5282 //
5283 // Create Event
5284 //
5285 Status = gBS->CreateEvent (
5286 EVT_NOTIFY_SIGNAL,
5287 TPL_NOTIFY,
5288 ScsiDiskNotify,
5289 Request,
5290 &AsyncIoEvent
5291 );
5292 if (EFI_ERROR (Status)) {
5293 goto ErrorExit;
5294 }
5295
5296 Status = ScsiRead16CommandEx (
5297 ScsiDiskDevice->ScsiIo,
5298 Request->Timeout,
5299 Request->SenseData,
5300 &Request->SenseDataLength,
5301 &Request->HostAdapterStatus,
5302 &Request->TargetStatus,
5303 Request->InBuffer,
5304 &Request->DataLength,
5305 Request->StartLba,
5306 Request->SectorCount,
5307 AsyncIoEvent
5308 );
5309 if (EFI_ERROR (Status)) {
5310 goto ErrorExit;
5311 }
5312
5313 return EFI_SUCCESS;
5314
5315 ErrorExit:
5316 if (AsyncIoEvent != NULL) {
5317 gBS->CloseEvent (AsyncIoEvent);
5318 }
5319
5320 if (Request != NULL) {
5321 if (Request->SenseData != NULL) {
5322 FreePool (Request->SenseData);
5323 }
5324
5325 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5326 RemoveEntryList (&Request->Link);
5327 gBS->RestoreTPL (OldTpl);
5328
5329 FreePool (Request);
5330 }
5331
5332 return Status;
5333 }
5334
5335 /**
5336 Submit Async Write(16) command.
5337
5338 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5339 @param Timeout The time to complete the command.
5340 @param TimesRetry The number of times the command has been retried.
5341 @param DataBuffer The buffer contains the data to write.
5342 @param DataLength The length of buffer.
5343 @param StartLba The start logic block address.
5344 @param SectorCount The number of blocks to write.
5345 @param BlkIo2Req The upstream BlockIo2 request.
5346 @param Token The pointer to the token associated with the
5347 non-blocking read request.
5348
5349 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5350 lack of resources.
5351 @return others Status returned by calling
5352 ScsiWrite16CommandEx().
5353
5354 **/
5355 EFI_STATUS
5356 ScsiDiskAsyncWrite16 (
5357 IN SCSI_DISK_DEV *ScsiDiskDevice,
5358 IN UINT64 Timeout,
5359 IN UINT8 TimesRetry,
5360 IN UINT8 *DataBuffer,
5361 IN UINT32 DataLength,
5362 IN UINT64 StartLba,
5363 IN UINT32 SectorCount,
5364 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
5365 IN EFI_BLOCK_IO2_TOKEN *Token
5366 )
5367 {
5368 EFI_STATUS Status;
5369 SCSI_ASYNC_RW_REQUEST *Request;
5370 EFI_EVENT AsyncIoEvent;
5371 EFI_TPL OldTpl;
5372
5373 AsyncIoEvent = NULL;
5374
5375 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5376 if (Request == NULL) {
5377 return EFI_OUT_OF_RESOURCES;
5378 }
5379
5380 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5381 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5382 gBS->RestoreTPL (OldTpl);
5383
5384 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
5385 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
5386 if (Request->SenseData == NULL) {
5387 Status = EFI_OUT_OF_RESOURCES;
5388 goto ErrorExit;
5389 }
5390
5391 Request->ScsiDiskDevice = ScsiDiskDevice;
5392 Request->Timeout = Timeout;
5393 Request->TimesRetry = TimesRetry;
5394 Request->OutBuffer = DataBuffer;
5395 Request->DataLength = DataLength;
5396 Request->StartLba = StartLba;
5397 Request->SectorCount = SectorCount;
5398 Request->BlkIo2Req = BlkIo2Req;
5399
5400 //
5401 // Create Event
5402 //
5403 Status = gBS->CreateEvent (
5404 EVT_NOTIFY_SIGNAL,
5405 TPL_NOTIFY,
5406 ScsiDiskNotify,
5407 Request,
5408 &AsyncIoEvent
5409 );
5410 if (EFI_ERROR (Status)) {
5411 goto ErrorExit;
5412 }
5413
5414 Status = ScsiWrite16CommandEx (
5415 ScsiDiskDevice->ScsiIo,
5416 Request->Timeout,
5417 Request->SenseData,
5418 &Request->SenseDataLength,
5419 &Request->HostAdapterStatus,
5420 &Request->TargetStatus,
5421 Request->OutBuffer,
5422 &Request->DataLength,
5423 Request->StartLba,
5424 Request->SectorCount,
5425 AsyncIoEvent
5426 );
5427 if (EFI_ERROR (Status)) {
5428 goto ErrorExit;
5429 }
5430
5431 return EFI_SUCCESS;
5432
5433 ErrorExit:
5434 if (AsyncIoEvent != NULL) {
5435 gBS->CloseEvent (AsyncIoEvent);
5436 }
5437
5438 if (Request != NULL) {
5439 if (Request->SenseData != NULL) {
5440 FreePool (Request->SenseData);
5441 }
5442
5443 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5444 RemoveEntryList (&Request->Link);
5445 gBS->RestoreTPL (OldTpl);
5446
5447 FreePool (Request);
5448 }
5449
5450 return Status;
5451 }
5452
5453 /**
5454 Check sense key to find if media presents.
5455
5456 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5457 @param SenseCounts The number of sense key
5458
5459 @retval TRUE NOT any media
5460 @retval FALSE Media presents
5461 **/
5462 BOOLEAN
5463 ScsiDiskIsNoMedia (
5464 IN EFI_SCSI_SENSE_DATA *SenseData,
5465 IN UINTN SenseCounts
5466 )
5467 {
5468 EFI_SCSI_SENSE_DATA *SensePtr;
5469 UINTN Index;
5470 BOOLEAN IsNoMedia;
5471
5472 IsNoMedia = FALSE;
5473 SensePtr = SenseData;
5474
5475 for (Index = 0; Index < SenseCounts; Index++) {
5476 //
5477 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
5478 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
5479 //
5480 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
5481 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA))
5482 {
5483 IsNoMedia = TRUE;
5484 }
5485
5486 SensePtr++;
5487 }
5488
5489 return IsNoMedia;
5490 }
5491
5492 /**
5493 Parse sense key.
5494
5495 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5496 @param SenseCounts The number of sense key
5497
5498 @retval TRUE Error
5499 @retval FALSE NOT error
5500
5501 **/
5502 BOOLEAN
5503 ScsiDiskIsMediaError (
5504 IN EFI_SCSI_SENSE_DATA *SenseData,
5505 IN UINTN SenseCounts
5506 )
5507 {
5508 EFI_SCSI_SENSE_DATA *SensePtr;
5509 UINTN Index;
5510 BOOLEAN IsError;
5511
5512 IsError = FALSE;
5513 SensePtr = SenseData;
5514
5515 for (Index = 0; Index < SenseCounts; Index++) {
5516 switch (SensePtr->Sense_Key) {
5517 case EFI_SCSI_SK_MEDIUM_ERROR:
5518 //
5519 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
5520 //
5521 switch (SensePtr->Addnl_Sense_Code) {
5522 //
5523 // fall through
5524 //
5525 case EFI_SCSI_ASC_MEDIA_ERR1:
5526
5527 //
5528 // fall through
5529 //
5530 case EFI_SCSI_ASC_MEDIA_ERR2:
5531
5532 //
5533 // fall through
5534 //
5535 case EFI_SCSI_ASC_MEDIA_ERR3:
5536 case EFI_SCSI_ASC_MEDIA_ERR4:
5537 IsError = TRUE;
5538 break;
5539
5540 default:
5541 break;
5542 }
5543
5544 break;
5545
5546 case EFI_SCSI_SK_NOT_READY:
5547 //
5548 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5549 //
5550 switch (SensePtr->Addnl_Sense_Code) {
5551 //
5552 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
5553 //
5554 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
5555 IsError = TRUE;
5556 break;
5557
5558 default:
5559 break;
5560 }
5561
5562 break;
5563
5564 default:
5565 break;
5566 }
5567
5568 SensePtr++;
5569 }
5570
5571 return IsError;
5572 }
5573
5574 /**
5575 Check sense key to find if hardware error happens.
5576
5577 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5578 @param SenseCounts The number of sense key
5579
5580 @retval TRUE Hardware error exits.
5581 @retval FALSE NO error.
5582
5583 **/
5584 BOOLEAN
5585 ScsiDiskIsHardwareError (
5586 IN EFI_SCSI_SENSE_DATA *SenseData,
5587 IN UINTN SenseCounts
5588 )
5589 {
5590 EFI_SCSI_SENSE_DATA *SensePtr;
5591 UINTN Index;
5592 BOOLEAN IsError;
5593
5594 IsError = FALSE;
5595 SensePtr = SenseData;
5596
5597 for (Index = 0; Index < SenseCounts; Index++) {
5598 //
5599 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
5600 //
5601 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
5602 IsError = TRUE;
5603 }
5604
5605 SensePtr++;
5606 }
5607
5608 return IsError;
5609 }
5610
5611 /**
5612 Check sense key to find if media has changed.
5613
5614 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5615 @param SenseCounts The number of sense key
5616
5617 @retval TRUE Media is changed.
5618 @retval FALSE Media is NOT changed.
5619 **/
5620 BOOLEAN
5621 ScsiDiskIsMediaChange (
5622 IN EFI_SCSI_SENSE_DATA *SenseData,
5623 IN UINTN SenseCounts
5624 )
5625 {
5626 EFI_SCSI_SENSE_DATA *SensePtr;
5627 UINTN Index;
5628 BOOLEAN IsMediaChanged;
5629
5630 IsMediaChanged = FALSE;
5631 SensePtr = SenseData;
5632
5633 for (Index = 0; Index < SenseCounts; Index++) {
5634 //
5635 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5636 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5637 //
5638 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5639 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE))
5640 {
5641 IsMediaChanged = TRUE;
5642 }
5643
5644 SensePtr++;
5645 }
5646
5647 return IsMediaChanged;
5648 }
5649
5650 /**
5651 Check sense key to find if reset happens.
5652
5653 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5654 @param SenseCounts The number of sense key
5655
5656 @retval TRUE It is reset before.
5657 @retval FALSE It is NOT reset before.
5658
5659 **/
5660 BOOLEAN
5661 ScsiDiskIsResetBefore (
5662 IN EFI_SCSI_SENSE_DATA *SenseData,
5663 IN UINTN SenseCounts
5664 )
5665 {
5666 EFI_SCSI_SENSE_DATA *SensePtr;
5667 UINTN Index;
5668 BOOLEAN IsResetBefore;
5669
5670 IsResetBefore = FALSE;
5671 SensePtr = SenseData;
5672
5673 for (Index = 0; Index < SenseCounts; Index++) {
5674 //
5675 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5676 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5677 //
5678 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5679 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET))
5680 {
5681 IsResetBefore = TRUE;
5682 }
5683
5684 SensePtr++;
5685 }
5686
5687 return IsResetBefore;
5688 }
5689
5690 /**
5691 Check sense key to find if the drive is ready.
5692
5693 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5694 @param SenseCounts The number of sense key
5695 @param RetryLater The flag means if need a retry
5696
5697 @retval TRUE Drive is ready.
5698 @retval FALSE Drive is NOT ready.
5699
5700 **/
5701 BOOLEAN
5702 ScsiDiskIsDriveReady (
5703 IN EFI_SCSI_SENSE_DATA *SenseData,
5704 IN UINTN SenseCounts,
5705 OUT BOOLEAN *RetryLater
5706 )
5707 {
5708 EFI_SCSI_SENSE_DATA *SensePtr;
5709 UINTN Index;
5710 BOOLEAN IsReady;
5711
5712 IsReady = TRUE;
5713 *RetryLater = FALSE;
5714 SensePtr = SenseData;
5715
5716 for (Index = 0; Index < SenseCounts; Index++) {
5717 switch (SensePtr->Sense_Key) {
5718 case EFI_SCSI_SK_NOT_READY:
5719 //
5720 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5721 //
5722 switch (SensePtr->Addnl_Sense_Code) {
5723 case EFI_SCSI_ASC_NOT_READY:
5724 //
5725 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5726 //
5727 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
5728 case EFI_SCSI_ASCQ_IN_PROGRESS:
5729 //
5730 // Additional Sense Code Qualifier is
5731 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5732 //
5733 IsReady = FALSE;
5734 *RetryLater = TRUE;
5735 break;
5736
5737 default:
5738 IsReady = FALSE;
5739 *RetryLater = FALSE;
5740 break;
5741 }
5742
5743 break;
5744
5745 default:
5746 break;
5747 }
5748
5749 break;
5750
5751 default:
5752 break;
5753 }
5754
5755 SensePtr++;
5756 }
5757
5758 return IsReady;
5759 }
5760
5761 /**
5762 Check sense key to find if it has sense key.
5763
5764 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
5765 @param SenseCounts - The number of sense key
5766
5767 @retval TRUE It has sense key.
5768 @retval FALSE It has NOT any sense key.
5769
5770 **/
5771 BOOLEAN
5772 ScsiDiskHaveSenseKey (
5773 IN EFI_SCSI_SENSE_DATA *SenseData,
5774 IN UINTN SenseCounts
5775 )
5776 {
5777 EFI_SCSI_SENSE_DATA *SensePtr;
5778 UINTN Index;
5779 BOOLEAN HaveSenseKey;
5780
5781 if (SenseCounts == 0) {
5782 HaveSenseKey = FALSE;
5783 } else {
5784 HaveSenseKey = TRUE;
5785 }
5786
5787 SensePtr = SenseData;
5788
5789 for (Index = 0; Index < SenseCounts; Index++) {
5790 //
5791 // Sense Key is SK_NO_SENSE (0x0)
5792 //
5793 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
5794 (Index == 0))
5795 {
5796 HaveSenseKey = FALSE;
5797 }
5798
5799 SensePtr++;
5800 }
5801
5802 return HaveSenseKey;
5803 }
5804
5805 /**
5806 Release resource about disk device.
5807
5808 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5809
5810 **/
5811 VOID
5812 ReleaseScsiDiskDeviceResources (
5813 IN SCSI_DISK_DEV *ScsiDiskDevice
5814 )
5815 {
5816 if (ScsiDiskDevice == NULL) {
5817 return;
5818 }
5819
5820 if (ScsiDiskDevice->SenseData != NULL) {
5821 FreePool (ScsiDiskDevice->SenseData);
5822 ScsiDiskDevice->SenseData = NULL;
5823 }
5824
5825 if (ScsiDiskDevice->ControllerNameTable != NULL) {
5826 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
5827 ScsiDiskDevice->ControllerNameTable = NULL;
5828 }
5829
5830 FreePool (ScsiDiskDevice);
5831
5832 ScsiDiskDevice = NULL;
5833 }
5834
5835 /**
5836 Determine if Block Io & Block Io2 should be produced.
5837
5838
5839 @param ChildHandle Child Handle to retrieve Parent information.
5840
5841 @retval TRUE Should produce Block Io & Block Io2.
5842 @retval FALSE Should not produce Block Io & Block Io2.
5843
5844 **/
5845 BOOLEAN
5846 DetermineInstallBlockIo (
5847 IN EFI_HANDLE ChildHandle
5848 )
5849 {
5850 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
5851 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
5852
5853 //
5854 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5855 // check its attribute, logic or physical.
5856 //
5857 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
5858 if (ExtScsiPassThru != NULL) {
5859 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5860 return TRUE;
5861 }
5862 }
5863
5864 //
5865 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5866 // check its attribute, logic or physical.
5867 //
5868 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
5869 if (ScsiPassThru != NULL) {
5870 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5871 return TRUE;
5872 }
5873 }
5874
5875 return FALSE;
5876 }
5877
5878 /**
5879 Search protocol database and check to see if the protocol
5880 specified by ProtocolGuid is present on a ControllerHandle and opened by
5881 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5882 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5883 will be opened on it.
5884
5885
5886 @param ProtocolGuid ProtocolGuid pointer.
5887 @param ChildHandle Child Handle to retrieve Parent information.
5888
5889 **/
5890 VOID *
5891 EFIAPI
5892 GetParentProtocol (
5893 IN EFI_GUID *ProtocolGuid,
5894 IN EFI_HANDLE ChildHandle
5895 )
5896 {
5897 UINTN Index;
5898 UINTN HandleCount;
5899 VOID *Interface;
5900 EFI_STATUS Status;
5901 EFI_HANDLE *HandleBuffer;
5902
5903 //
5904 // Retrieve the list of all handles from the handle database
5905 //
5906 Status = gBS->LocateHandleBuffer (
5907 ByProtocol,
5908 ProtocolGuid,
5909 NULL,
5910 &HandleCount,
5911 &HandleBuffer
5912 );
5913
5914 if (EFI_ERROR (Status)) {
5915 return NULL;
5916 }
5917
5918 //
5919 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5920 //
5921 for (Index = 0; Index < HandleCount; Index++) {
5922 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
5923 if (!EFI_ERROR (Status)) {
5924 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
5925 if (!EFI_ERROR (Status)) {
5926 gBS->FreePool (HandleBuffer);
5927 return Interface;
5928 }
5929 }
5930 }
5931
5932 gBS->FreePool (HandleBuffer);
5933 return NULL;
5934 }
5935
5936 /**
5937 Determine if EFI Erase Block Protocol should be produced.
5938
5939 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5940 @param ChildHandle Handle of device.
5941
5942 @retval TRUE Should produce EFI Erase Block Protocol.
5943 @retval FALSE Should not produce EFI Erase Block Protocol.
5944
5945 **/
5946 BOOLEAN
5947 DetermineInstallEraseBlock (
5948 IN SCSI_DISK_DEV *ScsiDiskDevice,
5949 IN EFI_HANDLE ChildHandle
5950 )
5951 {
5952 UINT8 HostAdapterStatus;
5953 UINT8 TargetStatus;
5954 EFI_STATUS CommandStatus;
5955 EFI_STATUS Status;
5956 BOOLEAN UfsDevice;
5957 BOOLEAN RetVal;
5958 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
5959 UINT8 SenseDataLength;
5960 UINT32 DataLength16;
5961 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
5962
5963 UfsDevice = FALSE;
5964 RetVal = TRUE;
5965 CapacityData16 = NULL;
5966
5967 //
5968 // UNMAP command is not supported by any of the UFS WLUNs.
5969 //
5970 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
5971 RetVal = FALSE;
5972 goto Done;
5973 }
5974
5975 Status = gBS->HandleProtocol (
5976 ChildHandle,
5977 &gEfiDevicePathProtocolGuid,
5978 (VOID **)&DevicePathNode
5979 );
5980 //
5981 // Device Path protocol must be installed on the device handle.
5982 //
5983 ASSERT_EFI_ERROR (Status);
5984
5985 while (!IsDevicePathEndType (DevicePathNode)) {
5986 //
5987 // For now, only support Erase Block Protocol on UFS devices.
5988 //
5989 if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
5990 (DevicePathNode->SubType == MSG_UFS_DP))
5991 {
5992 UfsDevice = TRUE;
5993 break;
5994 }
5995
5996 DevicePathNode = NextDevicePathNode (DevicePathNode);
5997 }
5998
5999 if (!UfsDevice) {
6000 RetVal = FALSE;
6001 goto Done;
6002 }
6003
6004 //
6005 // Check whether the erase functionality is enabled on the UFS device.
6006 //
6007 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
6008 if (CapacityData16 == NULL) {
6009 RetVal = FALSE;
6010 goto Done;
6011 }
6012
6013 SenseDataLength = 0;
6014 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
6015 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
6016
6017 CommandStatus = ScsiReadCapacity16Command (
6018 ScsiDiskDevice->ScsiIo,
6019 SCSI_DISK_TIMEOUT,
6020 NULL,
6021 &SenseDataLength,
6022 &HostAdapterStatus,
6023 &TargetStatus,
6024 (VOID *)CapacityData16,
6025 &DataLength16,
6026 FALSE
6027 );
6028
6029 if (CommandStatus == EFI_SUCCESS) {
6030 //
6031 // Universal Flash Storage (UFS) Version 2.0
6032 // Section 11.3.9.2
6033 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
6034 //
6035 if (((CapacityData16->LowestAlignLogic2 & BIT7) == 0) ||
6036 ((CapacityData16->LowestAlignLogic2 & BIT6) == 0))
6037 {
6038 DEBUG ((
6039 DEBUG_VERBOSE,
6040 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
6041 CapacityData16->LowestAlignLogic2
6042 ));
6043
6044 RetVal = FALSE;
6045 goto Done;
6046 }
6047 } else {
6048 DEBUG ((
6049 DEBUG_VERBOSE,
6050 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
6051 CommandStatus
6052 ));
6053
6054 RetVal = FALSE;
6055 goto Done;
6056 }
6057
6058 //
6059 // Check whether the UFS device server implements the UNMAP command.
6060 //
6061 if ((ScsiDiskDevice->UnmapInfo.MaxLbaCnt == 0) ||
6062 (ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt == 0))
6063 {
6064 DEBUG ((
6065 DEBUG_VERBOSE,
6066 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
6067 ));
6068
6069 RetVal = FALSE;
6070 goto Done;
6071 }
6072
6073 Done:
6074 if (CapacityData16 != NULL) {
6075 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
6076 }
6077
6078 return RetVal;
6079 }
6080
6081 /**
6082 Determine if EFI Storage Security Command Protocol should be produced.
6083
6084 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
6085 @param ChildHandle Handle of device.
6086
6087 @retval TRUE Should produce EFI Storage Security Command Protocol.
6088 @retval FALSE Should not produce EFI Storage Security Command Protocol.
6089
6090 **/
6091 BOOLEAN
6092 DetermineInstallStorageSecurity (
6093 IN SCSI_DISK_DEV *ScsiDiskDevice,
6094 IN EFI_HANDLE ChildHandle
6095 )
6096 {
6097 EFI_STATUS Status;
6098 UFS_DEVICE_PATH *UfsDevice;
6099 BOOLEAN RetVal;
6100 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
6101
6102 UfsDevice = NULL;
6103 RetVal = TRUE;
6104
6105 Status = gBS->HandleProtocol (
6106 ChildHandle,
6107 &gEfiDevicePathProtocolGuid,
6108 (VOID **)&DevicePathNode
6109 );
6110 //
6111 // Device Path protocol must be installed on the device handle.
6112 //
6113 ASSERT_EFI_ERROR (Status);
6114
6115 while (!IsDevicePathEndType (DevicePathNode)) {
6116 //
6117 // For now, only support Storage Security Command Protocol on UFS devices.
6118 //
6119 if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
6120 (DevicePathNode->SubType == MSG_UFS_DP))
6121 {
6122 UfsDevice = (UFS_DEVICE_PATH *)DevicePathNode;
6123 break;
6124 }
6125
6126 DevicePathNode = NextDevicePathNode (DevicePathNode);
6127 }
6128
6129 if (UfsDevice == NULL) {
6130 RetVal = FALSE;
6131 goto Done;
6132 }
6133
6134 if (UfsDevice->Lun != UFS_WLUN_RPMB) {
6135 RetVal = FALSE;
6136 }
6137
6138 Done:
6139 return RetVal;
6140 }
6141
6142 /**
6143 Provides inquiry information for the controller type.
6144
6145 This function is used by the IDE bus driver to get inquiry data. Data format
6146 of Identify data is defined by the Interface GUID.
6147
6148 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6149 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
6150 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
6151
6152 @retval EFI_SUCCESS The command was accepted without any errors.
6153 @retval EFI_NOT_FOUND Device does not support this data class
6154 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
6155 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
6156
6157 **/
6158 EFI_STATUS
6159 EFIAPI
6160 ScsiDiskInfoInquiry (
6161 IN EFI_DISK_INFO_PROTOCOL *This,
6162 IN OUT VOID *InquiryData,
6163 IN OUT UINT32 *InquiryDataSize
6164 )
6165 {
6166 EFI_STATUS Status;
6167 SCSI_DISK_DEV *ScsiDiskDevice;
6168
6169 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
6170
6171 Status = EFI_BUFFER_TOO_SMALL;
6172 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
6173 Status = EFI_SUCCESS;
6174 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
6175 }
6176
6177 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
6178 return Status;
6179 }
6180
6181 /**
6182 Provides identify information for the controller type.
6183
6184 This function is used by the IDE bus driver to get identify data. Data format
6185 of Identify data is defined by the Interface GUID.
6186
6187 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
6188 instance.
6189 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
6190 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
6191 size.
6192
6193 @retval EFI_SUCCESS The command was accepted without any errors.
6194 @retval EFI_NOT_FOUND Device does not support this data class
6195 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
6196 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
6197
6198 **/
6199 EFI_STATUS
6200 EFIAPI
6201 ScsiDiskInfoIdentify (
6202 IN EFI_DISK_INFO_PROTOCOL *This,
6203 IN OUT VOID *IdentifyData,
6204 IN OUT UINT32 *IdentifyDataSize
6205 )
6206 {
6207 EFI_STATUS Status;
6208 SCSI_DISK_DEV *ScsiDiskDevice;
6209
6210 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
6211 //
6212 // Physical SCSI bus does not support this data class.
6213 //
6214 return EFI_NOT_FOUND;
6215 }
6216
6217 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
6218
6219 Status = EFI_BUFFER_TOO_SMALL;
6220 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
6221 Status = EFI_SUCCESS;
6222 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
6223 }
6224
6225 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
6226 return Status;
6227 }
6228
6229 /**
6230 Provides sense data information for the controller type.
6231
6232 This function is used by the IDE bus driver to get sense data.
6233 Data format of Sense data is defined by the Interface GUID.
6234
6235 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6236 @param[in, out] SenseData Pointer to the SenseData.
6237 @param[in, out] SenseDataSize Size of SenseData in bytes.
6238 @param[out] SenseDataNumber Pointer to the value for the sense data size.
6239
6240 @retval EFI_SUCCESS The command was accepted without any errors.
6241 @retval EFI_NOT_FOUND Device does not support this data class.
6242 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
6243 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
6244
6245 **/
6246 EFI_STATUS
6247 EFIAPI
6248 ScsiDiskInfoSenseData (
6249 IN EFI_DISK_INFO_PROTOCOL *This,
6250 IN OUT VOID *SenseData,
6251 IN OUT UINT32 *SenseDataSize,
6252 OUT UINT8 *SenseDataNumber
6253 )
6254 {
6255 return EFI_NOT_FOUND;
6256 }
6257
6258 /**
6259 This function is used by the IDE bus driver to get controller information.
6260
6261 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6262 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
6263 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
6264
6265 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
6266 @retval EFI_UNSUPPORTED This is not an IDE device.
6267
6268 **/
6269 EFI_STATUS
6270 EFIAPI
6271 ScsiDiskInfoWhichIde (
6272 IN EFI_DISK_INFO_PROTOCOL *This,
6273 OUT UINT32 *IdeChannel,
6274 OUT UINT32 *IdeDevice
6275 )
6276 {
6277 SCSI_DISK_DEV *ScsiDiskDevice;
6278
6279 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
6280 //
6281 // This is not an IDE physical device.
6282 //
6283 return EFI_UNSUPPORTED;
6284 }
6285
6286 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
6287 *IdeChannel = ScsiDiskDevice->Channel;
6288 *IdeDevice = ScsiDiskDevice->Device;
6289
6290 return EFI_SUCCESS;
6291 }
6292
6293 /**
6294 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
6295
6296 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
6297 implement Identify() interface for DiskInfo protocol. The ATA command is sent
6298 via SCSI Request Packet.
6299
6300 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
6301
6302 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
6303 @retval others Some error occurred during the identification that ATAPI device.
6304
6305 **/
6306 EFI_STATUS
6307 AtapiIdentifyDevice (
6308 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
6309 )
6310 {
6311 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
6312 UINT8 Cdb[6];
6313
6314 //
6315 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
6316 //
6317 ZeroMem (&CommandPacket, sizeof (CommandPacket));
6318 ZeroMem (Cdb, sizeof (Cdb));
6319
6320 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
6321 CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
6322 CommandPacket.Cdb = Cdb;
6323 CommandPacket.CdbLength = (UINT8)sizeof (Cdb);
6324 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
6325 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
6326
6327 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
6328 }
6329
6330 /**
6331 Initialize the installation of DiskInfo protocol.
6332
6333 This function prepares for the installation of DiskInfo protocol on the child handle.
6334 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
6335 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
6336 to be IDE/AHCI interface GUID.
6337
6338 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
6339 @param ChildHandle Child handle to install DiskInfo protocol.
6340
6341 **/
6342 VOID
6343 InitializeInstallDiskInfo (
6344 IN SCSI_DISK_DEV *ScsiDiskDevice,
6345 IN EFI_HANDLE ChildHandle
6346 )
6347 {
6348 EFI_STATUS Status;
6349 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
6350 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
6351 ATAPI_DEVICE_PATH *AtapiDevicePath;
6352 SATA_DEVICE_PATH *SataDevicePath;
6353 UINTN IdentifyRetry;
6354
6355 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathNode);
6356 //
6357 // Device Path protocol must be installed on the device handle.
6358 //
6359 ASSERT_EFI_ERROR (Status);
6360 //
6361 // Copy the DiskInfo protocol template.
6362 //
6363 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
6364
6365 while (!IsDevicePathEnd (DevicePathNode)) {
6366 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
6367 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
6368 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
6369 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
6370 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
6371 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP)))
6372 {
6373 IdentifyRetry = 3;
6374 do {
6375 //
6376 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
6377 // with IDE/AHCI interface GUID.
6378 //
6379 Status = AtapiIdentifyDevice (ScsiDiskDevice);
6380 if (!EFI_ERROR (Status)) {
6381 if (DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) {
6382 //
6383 // We find the valid ATAPI device path
6384 //
6385 AtapiDevicePath = (ATAPI_DEVICE_PATH *)ChildDevicePathNode;
6386 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
6387 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
6388 //
6389 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
6390 //
6391 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
6392 } else {
6393 //
6394 // We find the valid SATA device path
6395 //
6396 SataDevicePath = (SATA_DEVICE_PATH *)ChildDevicePathNode;
6397 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
6398 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
6399 //
6400 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
6401 //
6402 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
6403 }
6404
6405 return;
6406 }
6407 } while (--IdentifyRetry > 0);
6408 } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
6409 (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP))
6410 {
6411 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
6412 break;
6413 }
6414
6415 DevicePathNode = ChildDevicePathNode;
6416 }
6417
6418 return;
6419 }