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