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