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