]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
MdeModulePkg ScsiDiskDxe: Fix hang issue when reconnecting an ISCSI device
[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 for (Index = 0; Index < PageLength; Index++) {
1497 if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
1498 break;
1499 }
1500 }
1501
1502 //
1503 // Query the Block Limits VPD page
1504 //
1505 if (Index < PageLength) {
1506 BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1507 if (BlockLimits == NULL) {
1508 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1509 *NeedRetry = FALSE;
1510 return EFI_DEVICE_ERROR;
1511 }
1512 ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1513 InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
1514 SenseDataLength = 0;
1515 Status = ScsiInquiryCommandEx (
1516 ScsiDiskDevice->ScsiIo,
1517 SCSI_DISK_TIMEOUT,
1518 NULL,
1519 &SenseDataLength,
1520 &HostAdapterStatus,
1521 &TargetStatus,
1522 (VOID *) BlockLimits,
1523 &InquiryDataLength,
1524 TRUE,
1525 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1526 );
1527 if (!EFI_ERROR (Status)) {
1528 ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
1529 (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
1530 BlockLimits->OptimalTransferLengthGranularity1;
1531 }
1532
1533 FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1534 }
1535 }
1536
1537 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1538 }
1539 }
1540
1541 if (!EFI_ERROR (Status)) {
1542 return EFI_SUCCESS;
1543
1544 } else if (Status == EFI_NOT_READY) {
1545 *NeedRetry = TRUE;
1546 return EFI_DEVICE_ERROR;
1547
1548 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1549 *NeedRetry = FALSE;
1550 return EFI_DEVICE_ERROR;
1551 }
1552 //
1553 // go ahead to check HostAdapterStatus and TargetStatus
1554 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1555 //
1556
1557 Status = CheckHostAdapterStatus (HostAdapterStatus);
1558 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1559 *NeedRetry = TRUE;
1560 return EFI_DEVICE_ERROR;
1561 } else if (Status == EFI_DEVICE_ERROR) {
1562 //
1563 // reset the scsi channel
1564 //
1565 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1566 *NeedRetry = FALSE;
1567 return EFI_DEVICE_ERROR;
1568 }
1569
1570 Status = CheckTargetStatus (TargetStatus);
1571 if (Status == EFI_NOT_READY) {
1572 //
1573 // reset the scsi device
1574 //
1575 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1576 *NeedRetry = TRUE;
1577 return EFI_DEVICE_ERROR;
1578
1579 } else if (Status == EFI_DEVICE_ERROR) {
1580 *NeedRetry = FALSE;
1581 return EFI_DEVICE_ERROR;
1582 }
1583
1584 //
1585 // if goes here, meant ScsiInquiryCommand() failed.
1586 // if ScsiDiskRequestSenseKeys() succeeds at last,
1587 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1588 //
1589 MaxRetry = 3;
1590 for (Index = 0; Index < MaxRetry; Index++) {
1591 Status = ScsiDiskRequestSenseKeys (
1592 ScsiDiskDevice,
1593 NeedRetry,
1594 &SenseDataArray,
1595 &NumberOfSenseKeys,
1596 TRUE
1597 );
1598 if (!EFI_ERROR (Status)) {
1599 *NeedRetry = TRUE;
1600 return EFI_DEVICE_ERROR;
1601 }
1602
1603 if (!*NeedRetry) {
1604 return EFI_DEVICE_ERROR;
1605 }
1606 }
1607 //
1608 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1609 // set *NeedRetry = FALSE to avoid the outside caller try again.
1610 //
1611 *NeedRetry = FALSE;
1612 return EFI_DEVICE_ERROR;
1613 }
1614
1615 /**
1616 To test device.
1617
1618 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1619 When Test Unit Ready command encounters any error caused by host adapter or
1620 target, return error without retrieving Sense Keys.
1621
1622 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1623 @param NeedRetry The pointer of flag indicates try again
1624 @param SenseDataArray The pointer of an array of sense data
1625 @param NumberOfSenseKeys The pointer of the number of sense data array
1626
1627 @retval EFI_DEVICE_ERROR Indicates that error occurs
1628 @retval EFI_SUCCESS Successfully to test unit
1629
1630 **/
1631 EFI_STATUS
1632 ScsiDiskTestUnitReady (
1633 IN SCSI_DISK_DEV *ScsiDiskDevice,
1634 OUT BOOLEAN *NeedRetry,
1635 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1636 OUT UINTN *NumberOfSenseKeys
1637 )
1638 {
1639 EFI_STATUS Status;
1640 UINT8 SenseDataLength;
1641 UINT8 HostAdapterStatus;
1642 UINT8 TargetStatus;
1643 UINT8 Index;
1644 UINT8 MaxRetry;
1645
1646 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
1647 *NumberOfSenseKeys = 0;
1648
1649 //
1650 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1651 //
1652 Status = ScsiTestUnitReadyCommand (
1653 ScsiDiskDevice->ScsiIo,
1654 SCSI_DISK_TIMEOUT,
1655 ScsiDiskDevice->SenseData,
1656 &SenseDataLength,
1657 &HostAdapterStatus,
1658 &TargetStatus
1659 );
1660 //
1661 // no need to check HostAdapterStatus and TargetStatus
1662 //
1663 if (Status == EFI_NOT_READY) {
1664 *NeedRetry = TRUE;
1665 return EFI_DEVICE_ERROR;
1666
1667 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1668 *NeedRetry = FALSE;
1669 return EFI_DEVICE_ERROR;
1670 }
1671 //
1672 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1673 //
1674
1675 Status = CheckHostAdapterStatus (HostAdapterStatus);
1676 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1677 *NeedRetry = TRUE;
1678 return EFI_DEVICE_ERROR;
1679
1680 } else if (Status == EFI_DEVICE_ERROR) {
1681 //
1682 // reset the scsi channel
1683 //
1684 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1685 *NeedRetry = FALSE;
1686 return EFI_DEVICE_ERROR;
1687 }
1688
1689 Status = CheckTargetStatus (TargetStatus);
1690 if (Status == EFI_NOT_READY) {
1691 //
1692 // reset the scsi device
1693 //
1694 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1695 *NeedRetry = TRUE;
1696 return EFI_DEVICE_ERROR;
1697
1698 } else if (Status == EFI_DEVICE_ERROR) {
1699 *NeedRetry = FALSE;
1700 return EFI_DEVICE_ERROR;
1701 }
1702
1703 if (SenseDataLength != 0) {
1704 *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
1705 *SenseDataArray = ScsiDiskDevice->SenseData;
1706 return EFI_SUCCESS;
1707 }
1708
1709 MaxRetry = 3;
1710 for (Index = 0; Index < MaxRetry; Index++) {
1711 Status = ScsiDiskRequestSenseKeys (
1712 ScsiDiskDevice,
1713 NeedRetry,
1714 SenseDataArray,
1715 NumberOfSenseKeys,
1716 FALSE
1717 );
1718 if (!EFI_ERROR (Status)) {
1719 return EFI_SUCCESS;
1720 }
1721
1722 if (!*NeedRetry) {
1723 return EFI_DEVICE_ERROR;
1724 }
1725 }
1726 //
1727 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1728 // set *NeedRetry = FALSE to avoid the outside caller try again.
1729 //
1730 *NeedRetry = FALSE;
1731 return EFI_DEVICE_ERROR;
1732 }
1733
1734 /**
1735 Parsing Sense Keys which got from request sense command.
1736
1737 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1738 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1739 @param NumberOfSenseKeys The number of sense key
1740 @param Action The pointer of action which indicates what is need to do next
1741
1742 @retval EFI_DEVICE_ERROR Indicates that error occurs
1743 @retval EFI_SUCCESS Successfully to complete the parsing
1744
1745 **/
1746 EFI_STATUS
1747 DetectMediaParsingSenseKeys (
1748 OUT SCSI_DISK_DEV *ScsiDiskDevice,
1749 IN EFI_SCSI_SENSE_DATA *SenseData,
1750 IN UINTN NumberOfSenseKeys,
1751 OUT UINTN *Action
1752 )
1753 {
1754 BOOLEAN RetryLater;
1755
1756 //
1757 // Default is to read capacity, unless..
1758 //
1759 *Action = ACTION_READ_CAPACITY;
1760
1761 if (NumberOfSenseKeys == 0) {
1762 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
1763 *Action = ACTION_NO_ACTION;
1764 }
1765 return EFI_SUCCESS;
1766 }
1767
1768 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
1769 //
1770 // No Sense Key returned from last submitted command
1771 //
1772 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
1773 *Action = ACTION_NO_ACTION;
1774 }
1775 return EFI_SUCCESS;
1776 }
1777
1778 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
1779 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
1780 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
1781 *Action = ACTION_NO_ACTION;
1782 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1783 return EFI_SUCCESS;
1784 }
1785
1786 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
1787 ScsiDiskDevice->BlkIo.Media->MediaId++;
1788 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1789 return EFI_SUCCESS;
1790 }
1791
1792 if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
1793 *Action = ACTION_RETRY_COMMAND_LATER;
1794 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1795 return EFI_SUCCESS;
1796 }
1797
1798 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
1799 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
1800 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1801 return EFI_DEVICE_ERROR;
1802 }
1803
1804 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
1805 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1806 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1807 return EFI_DEVICE_ERROR;
1808 }
1809
1810 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
1811 if (RetryLater) {
1812 *Action = ACTION_RETRY_COMMAND_LATER;
1813 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1814 return EFI_SUCCESS;
1815 }
1816 *Action = ACTION_NO_ACTION;
1817 return EFI_DEVICE_ERROR;
1818 }
1819
1820 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1821 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
1822 return EFI_SUCCESS;
1823 }
1824
1825
1826 /**
1827 Send read capacity command to device and get the device parameter.
1828
1829 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1830 @param NeedRetry The pointer of flag indicates if need a retry
1831 @param SenseDataArray The pointer of an array of sense data
1832 @param NumberOfSenseKeys The number of sense key
1833
1834 @retval EFI_DEVICE_ERROR Indicates that error occurs
1835 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1836
1837 **/
1838 EFI_STATUS
1839 ScsiDiskReadCapacity (
1840 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1841 OUT BOOLEAN *NeedRetry,
1842 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1843 OUT UINTN *NumberOfSenseKeys
1844 )
1845 {
1846 UINT8 HostAdapterStatus;
1847 UINT8 TargetStatus;
1848 EFI_STATUS CommandStatus;
1849 EFI_STATUS Status;
1850 UINT8 Index;
1851 UINT8 MaxRetry;
1852 UINT8 SenseDataLength;
1853 UINT32 DataLength10;
1854 UINT32 DataLength16;
1855 EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
1856 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
1857
1858 CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1859 if (CapacityData10 == NULL) {
1860 *NeedRetry = FALSE;
1861 return EFI_DEVICE_ERROR;
1862 }
1863 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1864 if (CapacityData16 == NULL) {
1865 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1866 *NeedRetry = FALSE;
1867 return EFI_DEVICE_ERROR;
1868 }
1869
1870 SenseDataLength = 0;
1871 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
1872 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
1873 ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1874 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1875
1876 *NumberOfSenseKeys = 0;
1877 *NeedRetry = FALSE;
1878
1879 //
1880 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1881 // 16 byte command should be used to access large hard disk >2TB
1882 //
1883 CommandStatus = ScsiReadCapacityCommand (
1884 ScsiDiskDevice->ScsiIo,
1885 SCSI_DISK_TIMEOUT,
1886 NULL,
1887 &SenseDataLength,
1888 &HostAdapterStatus,
1889 &TargetStatus,
1890 (VOID *) CapacityData10,
1891 &DataLength10,
1892 FALSE
1893 );
1894
1895 ScsiDiskDevice->Cdb16Byte = FALSE;
1896 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
1897 (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
1898 //
1899 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1900 //
1901 ScsiDiskDevice->Cdb16Byte = TRUE;
1902 //
1903 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1904 // and LowestAlignedLba
1905 //
1906 CommandStatus = ScsiReadCapacity16Command (
1907 ScsiDiskDevice->ScsiIo,
1908 SCSI_DISK_TIMEOUT,
1909 NULL,
1910 &SenseDataLength,
1911 &HostAdapterStatus,
1912 &TargetStatus,
1913 (VOID *) CapacityData16,
1914 &DataLength16,
1915 FALSE
1916 );
1917 }
1918
1919 //
1920 // no need to check HostAdapterStatus and TargetStatus
1921 //
1922 if (CommandStatus == EFI_SUCCESS) {
1923 GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
1924 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1925 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1926 return EFI_SUCCESS;
1927 }
1928
1929 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1930 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1931
1932 if (CommandStatus == EFI_NOT_READY) {
1933 *NeedRetry = TRUE;
1934 return EFI_DEVICE_ERROR;
1935 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
1936 *NeedRetry = FALSE;
1937 return EFI_DEVICE_ERROR;
1938 }
1939
1940 //
1941 // go ahead to check HostAdapterStatus and TargetStatus
1942 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1943 //
1944
1945 Status = CheckHostAdapterStatus (HostAdapterStatus);
1946 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1947 *NeedRetry = TRUE;
1948 return EFI_DEVICE_ERROR;
1949
1950 } else if (Status == EFI_DEVICE_ERROR) {
1951 //
1952 // reset the scsi channel
1953 //
1954 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1955 *NeedRetry = FALSE;
1956 return EFI_DEVICE_ERROR;
1957 }
1958
1959 Status = CheckTargetStatus (TargetStatus);
1960 if (Status == EFI_NOT_READY) {
1961 //
1962 // reset the scsi device
1963 //
1964 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1965 *NeedRetry = TRUE;
1966 return EFI_DEVICE_ERROR;
1967
1968 } else if (Status == EFI_DEVICE_ERROR) {
1969 *NeedRetry = FALSE;
1970 return EFI_DEVICE_ERROR;
1971 }
1972
1973 //
1974 // if goes here, meant ScsiReadCapacityCommand() failed.
1975 // if ScsiDiskRequestSenseKeys() succeeds at last,
1976 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1977 //
1978 MaxRetry = 3;
1979 for (Index = 0; Index < MaxRetry; Index++) {
1980
1981 Status = ScsiDiskRequestSenseKeys (
1982 ScsiDiskDevice,
1983 NeedRetry,
1984 SenseDataArray,
1985 NumberOfSenseKeys,
1986 TRUE
1987 );
1988 if (!EFI_ERROR (Status)) {
1989 return EFI_SUCCESS;
1990 }
1991
1992 if (!*NeedRetry) {
1993 return EFI_DEVICE_ERROR;
1994 }
1995 }
1996 //
1997 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1998 // set *NeedRetry = FALSE to avoid the outside caller try again.
1999 //
2000 *NeedRetry = FALSE;
2001 return EFI_DEVICE_ERROR;
2002 }
2003
2004 /**
2005 Check the HostAdapter status and re-interpret it in EFI_STATUS.
2006
2007 @param HostAdapterStatus Host Adapter status
2008
2009 @retval EFI_SUCCESS Host adapter is OK.
2010 @retval EFI_TIMEOUT Timeout.
2011 @retval EFI_NOT_READY Adapter NOT ready.
2012 @retval EFI_DEVICE_ERROR Adapter device error.
2013
2014 **/
2015 EFI_STATUS
2016 CheckHostAdapterStatus (
2017 IN UINT8 HostAdapterStatus
2018 )
2019 {
2020 switch (HostAdapterStatus) {
2021 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
2022 return EFI_SUCCESS;
2023
2024 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
2025 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
2026 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
2027 return EFI_TIMEOUT;
2028
2029 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
2030 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
2031 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
2032 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
2033 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
2034 return EFI_NOT_READY;
2035
2036 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
2037 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
2038 return EFI_DEVICE_ERROR;
2039
2040 default:
2041 return EFI_SUCCESS;
2042 }
2043 }
2044
2045
2046 /**
2047 Check the target status and re-interpret it in EFI_STATUS.
2048
2049 @param TargetStatus Target status
2050
2051 @retval EFI_NOT_READY Device is NOT ready.
2052 @retval EFI_DEVICE_ERROR
2053 @retval EFI_SUCCESS
2054
2055 **/
2056 EFI_STATUS
2057 CheckTargetStatus (
2058 IN UINT8 TargetStatus
2059 )
2060 {
2061 switch (TargetStatus) {
2062 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
2063 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
2064 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
2065 return EFI_SUCCESS;
2066
2067 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
2068 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
2069 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
2070 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
2071 return EFI_NOT_READY;
2072
2073 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
2074 return EFI_DEVICE_ERROR;
2075
2076 default:
2077 return EFI_SUCCESS;
2078 }
2079 }
2080
2081
2082 /**
2083 Retrieve all sense keys from the device.
2084
2085 When encountering error during the process, if retrieve sense keys before
2086 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2087 and NeedRetry set to FALSE; otherwize, return the proper return status.
2088
2089 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2090 @param NeedRetry The pointer of flag indicates if need a retry
2091 @param SenseDataArray The pointer of an array of sense data
2092 @param NumberOfSenseKeys The number of sense key
2093 @param AskResetIfError The flag indicates if need reset when error occurs
2094
2095 @retval EFI_DEVICE_ERROR Indicates that error occurs
2096 @retval EFI_SUCCESS Successfully to request sense key
2097
2098 **/
2099 EFI_STATUS
2100 ScsiDiskRequestSenseKeys (
2101 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
2102 OUT BOOLEAN *NeedRetry,
2103 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
2104 OUT UINTN *NumberOfSenseKeys,
2105 IN BOOLEAN AskResetIfError
2106 )
2107 {
2108 EFI_SCSI_SENSE_DATA *PtrSenseData;
2109 UINT8 SenseDataLength;
2110 BOOLEAN SenseReq;
2111 EFI_STATUS Status;
2112 EFI_STATUS FallStatus;
2113 UINT8 HostAdapterStatus;
2114 UINT8 TargetStatus;
2115
2116 FallStatus = EFI_SUCCESS;
2117 SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
2118
2119 ZeroMem (
2120 ScsiDiskDevice->SenseData,
2121 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
2122 );
2123
2124 *NumberOfSenseKeys = 0;
2125 *SenseDataArray = ScsiDiskDevice->SenseData;
2126 Status = EFI_SUCCESS;
2127 PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
2128 if (PtrSenseData == NULL) {
2129 return EFI_DEVICE_ERROR;
2130 }
2131
2132 for (SenseReq = TRUE; SenseReq;) {
2133 ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
2134 Status = ScsiRequestSenseCommand (
2135 ScsiDiskDevice->ScsiIo,
2136 SCSI_DISK_TIMEOUT,
2137 PtrSenseData,
2138 &SenseDataLength,
2139 &HostAdapterStatus,
2140 &TargetStatus
2141 );
2142 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
2143 FallStatus = EFI_SUCCESS;
2144
2145 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2146 *NeedRetry = TRUE;
2147 FallStatus = EFI_DEVICE_ERROR;
2148
2149 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2150 *NeedRetry = FALSE;
2151 FallStatus = EFI_DEVICE_ERROR;
2152
2153 } else if (Status == EFI_DEVICE_ERROR) {
2154 if (AskResetIfError) {
2155 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2156 }
2157
2158 FallStatus = EFI_DEVICE_ERROR;
2159 }
2160
2161 if (EFI_ERROR (FallStatus)) {
2162 if (*NumberOfSenseKeys != 0) {
2163 *NeedRetry = FALSE;
2164 Status = EFI_SUCCESS;
2165 goto EXIT;
2166 } else {
2167 Status = EFI_DEVICE_ERROR;
2168 goto EXIT;
2169 }
2170 }
2171
2172 CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
2173 (*NumberOfSenseKeys) += 1;
2174
2175 //
2176 // no more sense key or number of sense keys exceeds predefined,
2177 // skip the loop.
2178 //
2179 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
2180 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
2181 SenseReq = FALSE;
2182 }
2183 }
2184
2185 EXIT:
2186 FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
2187 return Status;
2188 }
2189
2190
2191 /**
2192 Get information from media read capacity command.
2193
2194 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2195 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2196 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2197
2198 **/
2199 VOID
2200 GetMediaInfo (
2201 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
2202 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
2203 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
2204 )
2205 {
2206 UINT8 *Ptr;
2207
2208 if (!ScsiDiskDevice->Cdb16Byte) {
2209 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |
2210 (Capacity10->LastLba2 << 16) |
2211 (Capacity10->LastLba1 << 8) |
2212 Capacity10->LastLba0;
2213
2214 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
2215 (Capacity10->BlockSize2 << 16) |
2216 (Capacity10->BlockSize1 << 8) |
2217 Capacity10->BlockSize0;
2218 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
2219 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;
2220 } else {
2221 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
2222 *Ptr++ = Capacity16->LastLba0;
2223 *Ptr++ = Capacity16->LastLba1;
2224 *Ptr++ = Capacity16->LastLba2;
2225 *Ptr++ = Capacity16->LastLba3;
2226 *Ptr++ = Capacity16->LastLba4;
2227 *Ptr++ = Capacity16->LastLba5;
2228 *Ptr++ = Capacity16->LastLba6;
2229 *Ptr = Capacity16->LastLba7;
2230
2231 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
2232 (Capacity16->BlockSize2 << 16) |
2233 (Capacity16->BlockSize1 << 8) |
2234 Capacity16->BlockSize0;
2235
2236 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
2237 Capacity16->LowestAlignLogic1;
2238 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);
2239 }
2240
2241 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
2242 }
2243
2244 /**
2245 Parse Inquiry data.
2246
2247 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2248
2249 **/
2250 VOID
2251 ParseInquiryData (
2252 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
2253 )
2254 {
2255 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
2256 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
2257 }
2258
2259 /**
2260 Read sector from SCSI Disk.
2261
2262 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2263 @param Buffer The buffer to fill in the read out data
2264 @param Lba Logic block address
2265 @param NumberOfBlocks The number of blocks to read
2266
2267 @retval EFI_DEVICE_ERROR Indicates a device error.
2268 @retval EFI_SUCCESS Operation is successful.
2269
2270 **/
2271 EFI_STATUS
2272 ScsiDiskReadSectors (
2273 IN SCSI_DISK_DEV *ScsiDiskDevice,
2274 OUT VOID *Buffer,
2275 IN EFI_LBA Lba,
2276 IN UINTN NumberOfBlocks
2277 )
2278 {
2279 UINTN BlocksRemaining;
2280 UINT8 *PtrBuffer;
2281 UINT32 BlockSize;
2282 UINT32 ByteCount;
2283 UINT32 MaxBlock;
2284 UINT32 SectorCount;
2285 UINT32 NextSectorCount;
2286 UINT64 Timeout;
2287 EFI_STATUS Status;
2288 UINT8 Index;
2289 UINT8 MaxRetry;
2290 BOOLEAN NeedRetry;
2291
2292 Status = EFI_SUCCESS;
2293
2294 BlocksRemaining = NumberOfBlocks;
2295 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2296
2297 //
2298 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2299 //
2300 if (!ScsiDiskDevice->Cdb16Byte) {
2301 MaxBlock = 0xFFFF;
2302 } else {
2303 MaxBlock = 0xFFFFFFFF;
2304 }
2305
2306 PtrBuffer = Buffer;
2307
2308 while (BlocksRemaining > 0) {
2309
2310 if (BlocksRemaining <= MaxBlock) {
2311 if (!ScsiDiskDevice->Cdb16Byte) {
2312 SectorCount = (UINT16) BlocksRemaining;
2313 } else {
2314 SectorCount = (UINT32) BlocksRemaining;
2315 }
2316 } else {
2317 SectorCount = MaxBlock;
2318 }
2319
2320 ByteCount = SectorCount * BlockSize;
2321 //
2322 // |------------------------|-----------------|------------------|-----------------|
2323 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2324 // |------------------------|-----------------|------------------|-----------------|
2325 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2326 // |------------------------|-----------------|------------------|-----------------|
2327 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2328 // |------------------------|-----------------|------------------|-----------------|
2329 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2330 // |------------------------|-----------------|------------------|-----------------|
2331 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2332 // |------------------------|-----------------|------------------|-----------------|
2333 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2334 // |------------------------|-----------------|------------------|-----------------|
2335 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2336 // |------------------------|-----------------|------------------|-----------------|
2337 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2338 // |------------------------|-----------------|------------------|-----------------|
2339 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2340 // |------------------------|-----------------|------------------|-----------------|
2341 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2342 // |------------------------|-----------------|------------------|-----------------|
2343 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2344 // |------------------------|-----------------|------------------|-----------------|
2345 //
2346 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2347 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2348 // From the above table, we could know 2.1Mbytes per second is lowest one.
2349 // The timout value is rounded up to nearest integar and here an additional 30s is added
2350 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2351 // commands in the Standby/Idle mode.
2352 //
2353 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2354
2355 MaxRetry = 2;
2356 for (Index = 0; Index < MaxRetry; Index++) {
2357 if (!ScsiDiskDevice->Cdb16Byte) {
2358 Status = ScsiDiskRead10 (
2359 ScsiDiskDevice,
2360 &NeedRetry,
2361 Timeout,
2362 PtrBuffer,
2363 &ByteCount,
2364 (UINT32) Lba,
2365 SectorCount
2366 );
2367 } else {
2368 Status = ScsiDiskRead16 (
2369 ScsiDiskDevice,
2370 &NeedRetry,
2371 Timeout,
2372 PtrBuffer,
2373 &ByteCount,
2374 Lba,
2375 SectorCount
2376 );
2377 }
2378 if (!EFI_ERROR (Status)) {
2379 break;
2380 }
2381
2382 if (!NeedRetry) {
2383 return EFI_DEVICE_ERROR;
2384 }
2385
2386 //
2387 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2388 // lowered ByteCount on output, we must make sure that we lower
2389 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2390 // it is invalid to request more sectors in the CDB than the entire
2391 // transfer (ie. ByteCount) can carry.
2392 //
2393 // In addition, ByteCount is only expected to go down, or stay unchaged.
2394 // Therefore we don't need to update Timeout: the original timeout should
2395 // accommodate shorter transfers too.
2396 //
2397 NextSectorCount = ByteCount / BlockSize;
2398 if (NextSectorCount < SectorCount) {
2399 SectorCount = NextSectorCount;
2400 //
2401 // Account for any rounding down.
2402 //
2403 ByteCount = SectorCount * BlockSize;
2404 }
2405 }
2406
2407 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
2408 return EFI_DEVICE_ERROR;
2409 }
2410
2411 //
2412 // actual transferred sectors
2413 //
2414 SectorCount = ByteCount / BlockSize;
2415
2416 Lba += SectorCount;
2417 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2418 BlocksRemaining -= SectorCount;
2419 }
2420
2421 return EFI_SUCCESS;
2422 }
2423
2424 /**
2425 Write sector to SCSI Disk.
2426
2427 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2428 @param Buffer The buffer of data to be written into SCSI Disk
2429 @param Lba Logic block address
2430 @param NumberOfBlocks The number of blocks to read
2431
2432 @retval EFI_DEVICE_ERROR Indicates a device error.
2433 @retval EFI_SUCCESS Operation is successful.
2434
2435 **/
2436 EFI_STATUS
2437 ScsiDiskWriteSectors (
2438 IN SCSI_DISK_DEV *ScsiDiskDevice,
2439 IN VOID *Buffer,
2440 IN EFI_LBA Lba,
2441 IN UINTN NumberOfBlocks
2442 )
2443 {
2444 UINTN BlocksRemaining;
2445 UINT8 *PtrBuffer;
2446 UINT32 BlockSize;
2447 UINT32 ByteCount;
2448 UINT32 MaxBlock;
2449 UINT32 SectorCount;
2450 UINT32 NextSectorCount;
2451 UINT64 Timeout;
2452 EFI_STATUS Status;
2453 UINT8 Index;
2454 UINT8 MaxRetry;
2455 BOOLEAN NeedRetry;
2456
2457 Status = EFI_SUCCESS;
2458
2459 BlocksRemaining = NumberOfBlocks;
2460 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2461
2462 //
2463 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2464 //
2465 if (!ScsiDiskDevice->Cdb16Byte) {
2466 MaxBlock = 0xFFFF;
2467 } else {
2468 MaxBlock = 0xFFFFFFFF;
2469 }
2470
2471 PtrBuffer = Buffer;
2472
2473 while (BlocksRemaining > 0) {
2474
2475 if (BlocksRemaining <= MaxBlock) {
2476 if (!ScsiDiskDevice->Cdb16Byte) {
2477 SectorCount = (UINT16) BlocksRemaining;
2478 } else {
2479 SectorCount = (UINT32) BlocksRemaining;
2480 }
2481 } else {
2482 SectorCount = MaxBlock;
2483 }
2484
2485 ByteCount = SectorCount * BlockSize;
2486 //
2487 // |------------------------|-----------------|------------------|-----------------|
2488 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2489 // |------------------------|-----------------|------------------|-----------------|
2490 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2491 // |------------------------|-----------------|------------------|-----------------|
2492 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2493 // |------------------------|-----------------|------------------|-----------------|
2494 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2495 // |------------------------|-----------------|------------------|-----------------|
2496 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2497 // |------------------------|-----------------|------------------|-----------------|
2498 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2499 // |------------------------|-----------------|------------------|-----------------|
2500 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2501 // |------------------------|-----------------|------------------|-----------------|
2502 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2503 // |------------------------|-----------------|------------------|-----------------|
2504 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2505 // |------------------------|-----------------|------------------|-----------------|
2506 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2507 // |------------------------|-----------------|------------------|-----------------|
2508 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2509 // |------------------------|-----------------|------------------|-----------------|
2510 //
2511 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2512 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2513 // From the above table, we could know 2.1Mbytes per second is lowest one.
2514 // The timout value is rounded up to nearest integar and here an additional 30s is added
2515 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2516 // commands in the Standby/Idle mode.
2517 //
2518 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2519 MaxRetry = 2;
2520 for (Index = 0; Index < MaxRetry; Index++) {
2521 if (!ScsiDiskDevice->Cdb16Byte) {
2522 Status = ScsiDiskWrite10 (
2523 ScsiDiskDevice,
2524 &NeedRetry,
2525 Timeout,
2526 PtrBuffer,
2527 &ByteCount,
2528 (UINT32) Lba,
2529 SectorCount
2530 );
2531 } else {
2532 Status = ScsiDiskWrite16 (
2533 ScsiDiskDevice,
2534 &NeedRetry,
2535 Timeout,
2536 PtrBuffer,
2537 &ByteCount,
2538 Lba,
2539 SectorCount
2540 );
2541 }
2542 if (!EFI_ERROR (Status)) {
2543 break;
2544 }
2545
2546 if (!NeedRetry) {
2547 return EFI_DEVICE_ERROR;
2548 }
2549
2550 //
2551 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2552 // has lowered ByteCount on output, we must make sure that we lower
2553 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2554 // it is invalid to request more sectors in the CDB than the entire
2555 // transfer (ie. ByteCount) can carry.
2556 //
2557 // In addition, ByteCount is only expected to go down, or stay unchaged.
2558 // Therefore we don't need to update Timeout: the original timeout should
2559 // accommodate shorter transfers too.
2560 //
2561 NextSectorCount = ByteCount / BlockSize;
2562 if (NextSectorCount < SectorCount) {
2563 SectorCount = NextSectorCount;
2564 //
2565 // Account for any rounding down.
2566 //
2567 ByteCount = SectorCount * BlockSize;
2568 }
2569 }
2570
2571 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
2572 return EFI_DEVICE_ERROR;
2573 }
2574 //
2575 // actual transferred sectors
2576 //
2577 SectorCount = ByteCount / BlockSize;
2578
2579 Lba += SectorCount;
2580 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2581 BlocksRemaining -= SectorCount;
2582 }
2583
2584 return EFI_SUCCESS;
2585 }
2586
2587 /**
2588 Asynchronously read sector from SCSI Disk.
2589
2590 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2591 @param Buffer The buffer to fill in the read out data.
2592 @param Lba Logic block address.
2593 @param NumberOfBlocks The number of blocks to read.
2594 @param Token A pointer to the token associated with the
2595 non-blocking read request.
2596
2597 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2598 @retval EFI_DEVICE_ERROR Indicates a device error.
2599 @retval EFI_SUCCESS Operation is successful.
2600
2601 **/
2602 EFI_STATUS
2603 ScsiDiskAsyncReadSectors (
2604 IN SCSI_DISK_DEV *ScsiDiskDevice,
2605 OUT VOID *Buffer,
2606 IN EFI_LBA Lba,
2607 IN UINTN NumberOfBlocks,
2608 IN EFI_BLOCK_IO2_TOKEN *Token
2609 )
2610 {
2611 UINTN BlocksRemaining;
2612 UINT8 *PtrBuffer;
2613 UINT32 BlockSize;
2614 UINT32 ByteCount;
2615 UINT32 MaxBlock;
2616 UINT32 SectorCount;
2617 UINT64 Timeout;
2618 SCSI_BLKIO2_REQUEST *BlkIo2Req;
2619 EFI_STATUS Status;
2620 EFI_TPL OldTpl;
2621
2622 if ((Token == NULL) || (Token->Event == NULL)) {
2623 return EFI_INVALID_PARAMETER;
2624 }
2625
2626 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
2627 if (BlkIo2Req == NULL) {
2628 return EFI_OUT_OF_RESOURCES;
2629 }
2630
2631 BlkIo2Req->Token = Token;
2632
2633 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2634 InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);
2635 gBS->RestoreTPL (OldTpl);
2636
2637 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
2638
2639 Status = EFI_SUCCESS;
2640
2641 BlocksRemaining = NumberOfBlocks;
2642 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2643
2644 //
2645 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2646 // Command
2647 //
2648 if (!ScsiDiskDevice->Cdb16Byte) {
2649 MaxBlock = 0xFFFF;
2650 } else {
2651 MaxBlock = 0xFFFFFFFF;
2652 }
2653
2654 PtrBuffer = Buffer;
2655
2656 while (BlocksRemaining > 0) {
2657
2658 if (BlocksRemaining <= MaxBlock) {
2659 if (!ScsiDiskDevice->Cdb16Byte) {
2660 SectorCount = (UINT16) BlocksRemaining;
2661 } else {
2662 SectorCount = (UINT32) BlocksRemaining;
2663 }
2664 } else {
2665 SectorCount = MaxBlock;
2666 }
2667
2668 ByteCount = SectorCount * BlockSize;
2669 //
2670 // |------------------------|-----------------|------------------|-----------------|
2671 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2672 // |------------------------|-----------------|------------------|-----------------|
2673 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2674 // |------------------------|-----------------|------------------|-----------------|
2675 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2676 // |------------------------|-----------------|------------------|-----------------|
2677 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2678 // |------------------------|-----------------|------------------|-----------------|
2679 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2680 // |------------------------|-----------------|------------------|-----------------|
2681 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2682 // |------------------------|-----------------|------------------|-----------------|
2683 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2684 // |------------------------|-----------------|------------------|-----------------|
2685 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2686 // |------------------------|-----------------|------------------|-----------------|
2687 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2688 // |------------------------|-----------------|------------------|-----------------|
2689 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2690 // |------------------------|-----------------|------------------|-----------------|
2691 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2692 // |------------------------|-----------------|------------------|-----------------|
2693 //
2694 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2695 // we have to use the lowest transfer rate to calculate the possible
2696 // maximum timeout value for each operation.
2697 // From the above table, we could know 2.1Mbytes per second is lowest one.
2698 // The timout value is rounded up to nearest integar and here an additional
2699 // 30s is added to follow ATA spec in which it mentioned that the device
2700 // may take up to 30s to respond commands in the Standby/Idle mode.
2701 //
2702 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2703
2704 if (!ScsiDiskDevice->Cdb16Byte) {
2705 Status = ScsiDiskAsyncRead10 (
2706 ScsiDiskDevice,
2707 Timeout,
2708 0,
2709 PtrBuffer,
2710 ByteCount,
2711 (UINT32) Lba,
2712 SectorCount,
2713 BlkIo2Req,
2714 Token
2715 );
2716 } else {
2717 Status = ScsiDiskAsyncRead16 (
2718 ScsiDiskDevice,
2719 Timeout,
2720 0,
2721 PtrBuffer,
2722 ByteCount,
2723 Lba,
2724 SectorCount,
2725 BlkIo2Req,
2726 Token
2727 );
2728 }
2729 if (EFI_ERROR (Status)) {
2730 //
2731 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2732 // length of a SCSI I/O command is too large.
2733 // In this case, we retry sending the SCSI command with a data length
2734 // half of its previous value.
2735 //
2736 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
2737 if ((MaxBlock > 1) && (SectorCount > 1)) {
2738 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
2739 continue;
2740 }
2741 }
2742
2743 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2744 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
2745 //
2746 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
2747 // SCSI sub-task running. Otherwise, it will be freed in the callback
2748 // function ScsiDiskNotify().
2749 //
2750 RemoveEntryList (&BlkIo2Req->Link);
2751 FreePool (BlkIo2Req);
2752 BlkIo2Req = NULL;
2753 gBS->RestoreTPL (OldTpl);
2754
2755 //
2756 // It is safe to return error status to the caller, since there is no
2757 // previous SCSI sub-task executing.
2758 //
2759 Status = EFI_DEVICE_ERROR;
2760 goto Done;
2761 } else {
2762 gBS->RestoreTPL (OldTpl);
2763
2764 //
2765 // There are previous SCSI commands still running, EFI_SUCCESS should
2766 // be returned to make sure that the caller does not free resources
2767 // still using by these SCSI commands.
2768 //
2769 Status = EFI_SUCCESS;
2770 goto Done;
2771 }
2772 }
2773
2774 //
2775 // Sectors submitted for transfer
2776 //
2777 SectorCount = ByteCount / BlockSize;
2778
2779 Lba += SectorCount;
2780 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2781 BlocksRemaining -= SectorCount;
2782 }
2783
2784 Status = EFI_SUCCESS;
2785
2786 Done:
2787 if (BlkIo2Req != NULL) {
2788 BlkIo2Req->LastScsiRW = TRUE;
2789
2790 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2791 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
2792 RemoveEntryList (&BlkIo2Req->Link);
2793 FreePool (BlkIo2Req);
2794 BlkIo2Req = NULL;
2795
2796 gBS->SignalEvent (Token->Event);
2797 }
2798 gBS->RestoreTPL (OldTpl);
2799 }
2800
2801 return Status;
2802 }
2803
2804 /**
2805 Asynchronously write sector to SCSI Disk.
2806
2807 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2808 @param Buffer The buffer of data to be written into SCSI Disk.
2809 @param Lba Logic block address.
2810 @param NumberOfBlocks The number of blocks to read.
2811 @param Token A pointer to the token associated with the
2812 non-blocking read request.
2813
2814 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2815 @retval EFI_DEVICE_ERROR Indicates a device error.
2816 @retval EFI_SUCCESS Operation is successful.
2817
2818 **/
2819 EFI_STATUS
2820 ScsiDiskAsyncWriteSectors (
2821 IN SCSI_DISK_DEV *ScsiDiskDevice,
2822 IN VOID *Buffer,
2823 IN EFI_LBA Lba,
2824 IN UINTN NumberOfBlocks,
2825 IN EFI_BLOCK_IO2_TOKEN *Token
2826 )
2827 {
2828 UINTN BlocksRemaining;
2829 UINT8 *PtrBuffer;
2830 UINT32 BlockSize;
2831 UINT32 ByteCount;
2832 UINT32 MaxBlock;
2833 UINT32 SectorCount;
2834 UINT64 Timeout;
2835 SCSI_BLKIO2_REQUEST *BlkIo2Req;
2836 EFI_STATUS Status;
2837 EFI_TPL OldTpl;
2838
2839 if ((Token == NULL) || (Token->Event == NULL)) {
2840 return EFI_INVALID_PARAMETER;
2841 }
2842
2843 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
2844 if (BlkIo2Req == NULL) {
2845 return EFI_OUT_OF_RESOURCES;
2846 }
2847
2848 BlkIo2Req->Token = Token;
2849
2850 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2851 InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);
2852 gBS->RestoreTPL (OldTpl);
2853
2854 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
2855
2856 Status = EFI_SUCCESS;
2857
2858 BlocksRemaining = NumberOfBlocks;
2859 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2860
2861 //
2862 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2863 // Command
2864 //
2865 if (!ScsiDiskDevice->Cdb16Byte) {
2866 MaxBlock = 0xFFFF;
2867 } else {
2868 MaxBlock = 0xFFFFFFFF;
2869 }
2870
2871 PtrBuffer = Buffer;
2872
2873 while (BlocksRemaining > 0) {
2874
2875 if (BlocksRemaining <= MaxBlock) {
2876 if (!ScsiDiskDevice->Cdb16Byte) {
2877 SectorCount = (UINT16) BlocksRemaining;
2878 } else {
2879 SectorCount = (UINT32) BlocksRemaining;
2880 }
2881 } else {
2882 SectorCount = MaxBlock;
2883 }
2884
2885 ByteCount = SectorCount * BlockSize;
2886 //
2887 // |------------------------|-----------------|------------------|-----------------|
2888 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2889 // |------------------------|-----------------|------------------|-----------------|
2890 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2891 // |------------------------|-----------------|------------------|-----------------|
2892 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2893 // |------------------------|-----------------|------------------|-----------------|
2894 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2895 // |------------------------|-----------------|------------------|-----------------|
2896 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2897 // |------------------------|-----------------|------------------|-----------------|
2898 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2899 // |------------------------|-----------------|------------------|-----------------|
2900 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2901 // |------------------------|-----------------|------------------|-----------------|
2902 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2903 // |------------------------|-----------------|------------------|-----------------|
2904 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2905 // |------------------------|-----------------|------------------|-----------------|
2906 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2907 // |------------------------|-----------------|------------------|-----------------|
2908 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2909 // |------------------------|-----------------|------------------|-----------------|
2910 //
2911 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2912 // we have to use the lowest transfer rate to calculate the possible
2913 // maximum timeout value for each operation.
2914 // From the above table, we could know 2.1Mbytes per second is lowest one.
2915 // The timout value is rounded up to nearest integar and here an additional
2916 // 30s is added to follow ATA spec in which it mentioned that the device
2917 // may take up to 30s to respond commands in the Standby/Idle mode.
2918 //
2919 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2920
2921 if (!ScsiDiskDevice->Cdb16Byte) {
2922 Status = ScsiDiskAsyncWrite10 (
2923 ScsiDiskDevice,
2924 Timeout,
2925 0,
2926 PtrBuffer,
2927 ByteCount,
2928 (UINT32) Lba,
2929 SectorCount,
2930 BlkIo2Req,
2931 Token
2932 );
2933 } else {
2934 Status = ScsiDiskAsyncWrite16 (
2935 ScsiDiskDevice,
2936 Timeout,
2937 0,
2938 PtrBuffer,
2939 ByteCount,
2940 Lba,
2941 SectorCount,
2942 BlkIo2Req,
2943 Token
2944 );
2945 }
2946 if (EFI_ERROR (Status)) {
2947 //
2948 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2949 // length of a SCSI I/O command is too large.
2950 // In this case, we retry sending the SCSI command with a data length
2951 // half of its previous value.
2952 //
2953 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
2954 if ((MaxBlock > 1) && (SectorCount > 1)) {
2955 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
2956 continue;
2957 }
2958 }
2959
2960 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2961 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
2962 //
2963 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
2964 // SCSI sub-task running. Otherwise, it will be freed in the callback
2965 // function ScsiDiskNotify().
2966 //
2967 RemoveEntryList (&BlkIo2Req->Link);
2968 FreePool (BlkIo2Req);
2969 BlkIo2Req = NULL;
2970 gBS->RestoreTPL (OldTpl);
2971
2972 //
2973 // It is safe to return error status to the caller, since there is no
2974 // previous SCSI sub-task executing.
2975 //
2976 Status = EFI_DEVICE_ERROR;
2977 goto Done;
2978 } else {
2979 gBS->RestoreTPL (OldTpl);
2980
2981 //
2982 // There are previous SCSI commands still running, EFI_SUCCESS should
2983 // be returned to make sure that the caller does not free resources
2984 // still using by these SCSI commands.
2985 //
2986 Status = EFI_SUCCESS;
2987 goto Done;
2988 }
2989 }
2990
2991 //
2992 // Sectors submitted for transfer
2993 //
2994 SectorCount = ByteCount / BlockSize;
2995
2996 Lba += SectorCount;
2997 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2998 BlocksRemaining -= SectorCount;
2999 }
3000
3001 Status = EFI_SUCCESS;
3002
3003 Done:
3004 if (BlkIo2Req != NULL) {
3005 BlkIo2Req->LastScsiRW = TRUE;
3006
3007 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3008 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3009 RemoveEntryList (&BlkIo2Req->Link);
3010 FreePool (BlkIo2Req);
3011 BlkIo2Req = NULL;
3012
3013 gBS->SignalEvent (Token->Event);
3014 }
3015 gBS->RestoreTPL (OldTpl);
3016 }
3017
3018 return Status;
3019 }
3020
3021
3022 /**
3023 Submit Read(10) command.
3024
3025 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3026 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3027 @param Timeout The time to complete the command
3028 @param DataBuffer The buffer to fill with the read out data
3029 @param DataLength The length of buffer
3030 @param StartLba The start logic block address
3031 @param SectorCount The number of blocks to read
3032
3033 @return EFI_STATUS is returned by calling ScsiRead10Command().
3034 **/
3035 EFI_STATUS
3036 ScsiDiskRead10 (
3037 IN SCSI_DISK_DEV *ScsiDiskDevice,
3038 OUT BOOLEAN *NeedRetry,
3039 IN UINT64 Timeout,
3040 OUT UINT8 *DataBuffer,
3041 IN OUT UINT32 *DataLength,
3042 IN UINT32 StartLba,
3043 IN UINT32 SectorCount
3044 )
3045 {
3046 UINT8 SenseDataLength;
3047 EFI_STATUS Status;
3048 EFI_STATUS ReturnStatus;
3049 UINT8 HostAdapterStatus;
3050 UINT8 TargetStatus;
3051 UINTN Action;
3052
3053 //
3054 // Implement a backoff algorithem to resolve some compatibility issues that
3055 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3056 // big data in a single operation.
3057 // This algorithem will at first try to execute original request. If the request fails
3058 // with media error sense data or else, it will reduce the transfer length to half and
3059 // try again till the operation succeeds or fails with one sector transfer length.
3060 //
3061 BackOff:
3062 *NeedRetry = FALSE;
3063 Action = ACTION_NO_ACTION;
3064 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3065 ReturnStatus = ScsiRead10Command (
3066 ScsiDiskDevice->ScsiIo,
3067 Timeout,
3068 ScsiDiskDevice->SenseData,
3069 &SenseDataLength,
3070 &HostAdapterStatus,
3071 &TargetStatus,
3072 DataBuffer,
3073 DataLength,
3074 StartLba,
3075 SectorCount
3076 );
3077
3078 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3079 *NeedRetry = TRUE;
3080 return EFI_DEVICE_ERROR;
3081 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3082 *NeedRetry = FALSE;
3083 return ReturnStatus;
3084 }
3085
3086 //
3087 // go ahead to check HostAdapterStatus and TargetStatus
3088 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3089 //
3090 Status = CheckHostAdapterStatus (HostAdapterStatus);
3091 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3092 *NeedRetry = TRUE;
3093 return EFI_DEVICE_ERROR;
3094 } else if (Status == EFI_DEVICE_ERROR) {
3095 //
3096 // reset the scsi channel
3097 //
3098 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3099 *NeedRetry = FALSE;
3100 return EFI_DEVICE_ERROR;
3101 }
3102
3103 Status = CheckTargetStatus (TargetStatus);
3104 if (Status == EFI_NOT_READY) {
3105 //
3106 // reset the scsi device
3107 //
3108 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3109 *NeedRetry = TRUE;
3110 return EFI_DEVICE_ERROR;
3111 } else if (Status == EFI_DEVICE_ERROR) {
3112 *NeedRetry = FALSE;
3113 return EFI_DEVICE_ERROR;
3114 }
3115
3116 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3117 DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
3118 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3119 if (Action == ACTION_RETRY_COMMAND_LATER) {
3120 *NeedRetry = TRUE;
3121 return EFI_DEVICE_ERROR;
3122 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3123 if (SectorCount <= 1) {
3124 //
3125 // Jump out if the operation still fails with one sector transfer length.
3126 //
3127 *NeedRetry = FALSE;
3128 return EFI_DEVICE_ERROR;
3129 }
3130 //
3131 // Try again with half length if the sense data shows we need to retry.
3132 //
3133 SectorCount >>= 1;
3134 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3135 goto BackOff;
3136 } else {
3137 *NeedRetry = FALSE;
3138 return EFI_DEVICE_ERROR;
3139 }
3140 }
3141
3142 return ReturnStatus;
3143 }
3144
3145
3146 /**
3147 Submit Write(10) Command.
3148
3149 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3150 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3151 @param Timeout The time to complete the command
3152 @param DataBuffer The buffer to fill with the read out data
3153 @param DataLength The length of buffer
3154 @param StartLba The start logic block address
3155 @param SectorCount The number of blocks to write
3156
3157 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3158
3159 **/
3160 EFI_STATUS
3161 ScsiDiskWrite10 (
3162 IN SCSI_DISK_DEV *ScsiDiskDevice,
3163 OUT BOOLEAN *NeedRetry,
3164 IN UINT64 Timeout,
3165 IN UINT8 *DataBuffer,
3166 IN OUT UINT32 *DataLength,
3167 IN UINT32 StartLba,
3168 IN UINT32 SectorCount
3169 )
3170 {
3171 EFI_STATUS Status;
3172 EFI_STATUS ReturnStatus;
3173 UINT8 SenseDataLength;
3174 UINT8 HostAdapterStatus;
3175 UINT8 TargetStatus;
3176 UINTN Action;
3177
3178 //
3179 // Implement a backoff algorithem to resolve some compatibility issues that
3180 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3181 // big data in a single operation.
3182 // This algorithem will at first try to execute original request. If the request fails
3183 // with media error sense data or else, it will reduce the transfer length to half and
3184 // try again till the operation succeeds or fails with one sector transfer length.
3185 //
3186 BackOff:
3187 *NeedRetry = FALSE;
3188 Action = ACTION_NO_ACTION;
3189 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3190 ReturnStatus = ScsiWrite10Command (
3191 ScsiDiskDevice->ScsiIo,
3192 Timeout,
3193 ScsiDiskDevice->SenseData,
3194 &SenseDataLength,
3195 &HostAdapterStatus,
3196 &TargetStatus,
3197 DataBuffer,
3198 DataLength,
3199 StartLba,
3200 SectorCount
3201 );
3202 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3203 *NeedRetry = TRUE;
3204 return EFI_DEVICE_ERROR;
3205 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3206 *NeedRetry = FALSE;
3207 return ReturnStatus;
3208 }
3209
3210 //
3211 // go ahead to check HostAdapterStatus and TargetStatus
3212 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3213 //
3214 Status = CheckHostAdapterStatus (HostAdapterStatus);
3215 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3216 *NeedRetry = TRUE;
3217 return EFI_DEVICE_ERROR;
3218 } else if (Status == EFI_DEVICE_ERROR) {
3219 //
3220 // reset the scsi channel
3221 //
3222 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3223 *NeedRetry = FALSE;
3224 return EFI_DEVICE_ERROR;
3225 }
3226
3227 Status = CheckTargetStatus (TargetStatus);
3228 if (Status == EFI_NOT_READY) {
3229 //
3230 // reset the scsi device
3231 //
3232 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3233 *NeedRetry = TRUE;
3234 return EFI_DEVICE_ERROR;
3235 } else if (Status == EFI_DEVICE_ERROR) {
3236 *NeedRetry = FALSE;
3237 return EFI_DEVICE_ERROR;
3238 }
3239
3240 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3241 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
3242 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3243 if (Action == ACTION_RETRY_COMMAND_LATER) {
3244 *NeedRetry = TRUE;
3245 return EFI_DEVICE_ERROR;
3246 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3247 if (SectorCount <= 1) {
3248 //
3249 // Jump out if the operation still fails with one sector transfer length.
3250 //
3251 *NeedRetry = FALSE;
3252 return EFI_DEVICE_ERROR;
3253 }
3254 //
3255 // Try again with half length if the sense data shows we need to retry.
3256 //
3257 SectorCount >>= 1;
3258 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3259 goto BackOff;
3260 } else {
3261 *NeedRetry = FALSE;
3262 return EFI_DEVICE_ERROR;
3263 }
3264 }
3265
3266 return ReturnStatus;
3267 }
3268
3269
3270 /**
3271 Submit Read(16) command.
3272
3273 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3274 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3275 @param Timeout The time to complete the command
3276 @param DataBuffer The buffer to fill with the read out data
3277 @param DataLength The length of buffer
3278 @param StartLba The start logic block address
3279 @param SectorCount The number of blocks to read
3280
3281 @return EFI_STATUS is returned by calling ScsiRead16Command().
3282 **/
3283 EFI_STATUS
3284 ScsiDiskRead16 (
3285 IN SCSI_DISK_DEV *ScsiDiskDevice,
3286 OUT BOOLEAN *NeedRetry,
3287 IN UINT64 Timeout,
3288 OUT UINT8 *DataBuffer,
3289 IN OUT UINT32 *DataLength,
3290 IN UINT64 StartLba,
3291 IN UINT32 SectorCount
3292 )
3293 {
3294 UINT8 SenseDataLength;
3295 EFI_STATUS Status;
3296 EFI_STATUS ReturnStatus;
3297 UINT8 HostAdapterStatus;
3298 UINT8 TargetStatus;
3299 UINTN Action;
3300
3301 //
3302 // Implement a backoff algorithem to resolve some compatibility issues that
3303 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3304 // big data in a single operation.
3305 // This algorithem will at first try to execute original request. If the request fails
3306 // with media error sense data or else, it will reduce the transfer length to half and
3307 // try again till the operation succeeds or fails with one sector transfer length.
3308 //
3309 BackOff:
3310 *NeedRetry = FALSE;
3311 Action = ACTION_NO_ACTION;
3312 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3313 ReturnStatus = ScsiRead16Command (
3314 ScsiDiskDevice->ScsiIo,
3315 Timeout,
3316 ScsiDiskDevice->SenseData,
3317 &SenseDataLength,
3318 &HostAdapterStatus,
3319 &TargetStatus,
3320 DataBuffer,
3321 DataLength,
3322 StartLba,
3323 SectorCount
3324 );
3325 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3326 *NeedRetry = TRUE;
3327 return EFI_DEVICE_ERROR;
3328 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3329 *NeedRetry = FALSE;
3330 return ReturnStatus;
3331 }
3332
3333 //
3334 // go ahead to check HostAdapterStatus and TargetStatus
3335 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3336 //
3337 Status = CheckHostAdapterStatus (HostAdapterStatus);
3338 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3339 *NeedRetry = TRUE;
3340 return EFI_DEVICE_ERROR;
3341 } else if (Status == EFI_DEVICE_ERROR) {
3342 //
3343 // reset the scsi channel
3344 //
3345 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3346 *NeedRetry = FALSE;
3347 return EFI_DEVICE_ERROR;
3348 }
3349
3350 Status = CheckTargetStatus (TargetStatus);
3351 if (Status == EFI_NOT_READY) {
3352 //
3353 // reset the scsi device
3354 //
3355 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3356 *NeedRetry = TRUE;
3357 return EFI_DEVICE_ERROR;
3358 } else if (Status == EFI_DEVICE_ERROR) {
3359 *NeedRetry = FALSE;
3360 return EFI_DEVICE_ERROR;
3361 }
3362
3363 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3364 DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
3365 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3366 if (Action == ACTION_RETRY_COMMAND_LATER) {
3367 *NeedRetry = TRUE;
3368 return EFI_DEVICE_ERROR;
3369 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3370 if (SectorCount <= 1) {
3371 //
3372 // Jump out if the operation still fails with one sector transfer length.
3373 //
3374 *NeedRetry = FALSE;
3375 return EFI_DEVICE_ERROR;
3376 }
3377 //
3378 // Try again with half length if the sense data shows we need to retry.
3379 //
3380 SectorCount >>= 1;
3381 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3382 goto BackOff;
3383 } else {
3384 *NeedRetry = FALSE;
3385 return EFI_DEVICE_ERROR;
3386 }
3387 }
3388
3389 return ReturnStatus;
3390 }
3391
3392
3393 /**
3394 Submit Write(16) Command.
3395
3396 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3397 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3398 @param Timeout The time to complete the command
3399 @param DataBuffer The buffer to fill with the read out data
3400 @param DataLength The length of buffer
3401 @param StartLba The start logic block address
3402 @param SectorCount The number of blocks to write
3403
3404 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3405
3406 **/
3407 EFI_STATUS
3408 ScsiDiskWrite16 (
3409 IN SCSI_DISK_DEV *ScsiDiskDevice,
3410 OUT BOOLEAN *NeedRetry,
3411 IN UINT64 Timeout,
3412 IN UINT8 *DataBuffer,
3413 IN OUT UINT32 *DataLength,
3414 IN UINT64 StartLba,
3415 IN UINT32 SectorCount
3416 )
3417 {
3418 EFI_STATUS Status;
3419 EFI_STATUS ReturnStatus;
3420 UINT8 SenseDataLength;
3421 UINT8 HostAdapterStatus;
3422 UINT8 TargetStatus;
3423 UINTN Action;
3424
3425 //
3426 // Implement a backoff algorithem to resolve some compatibility issues that
3427 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3428 // big data in a single operation.
3429 // This algorithem will at first try to execute original request. If the request fails
3430 // with media error sense data or else, it will reduce the transfer length to half and
3431 // try again till the operation succeeds or fails with one sector transfer length.
3432 //
3433 BackOff:
3434 *NeedRetry = FALSE;
3435 Action = ACTION_NO_ACTION;
3436 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3437 ReturnStatus = ScsiWrite16Command (
3438 ScsiDiskDevice->ScsiIo,
3439 Timeout,
3440 ScsiDiskDevice->SenseData,
3441 &SenseDataLength,
3442 &HostAdapterStatus,
3443 &TargetStatus,
3444 DataBuffer,
3445 DataLength,
3446 StartLba,
3447 SectorCount
3448 );
3449 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3450 *NeedRetry = TRUE;
3451 return EFI_DEVICE_ERROR;
3452 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3453 *NeedRetry = FALSE;
3454 return ReturnStatus;
3455 }
3456
3457 //
3458 // go ahead to check HostAdapterStatus and TargetStatus
3459 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3460 //
3461 Status = CheckHostAdapterStatus (HostAdapterStatus);
3462 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3463 *NeedRetry = TRUE;
3464 return EFI_DEVICE_ERROR;
3465 } else if (Status == EFI_DEVICE_ERROR) {
3466 //
3467 // reset the scsi channel
3468 //
3469 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3470 *NeedRetry = FALSE;
3471 return EFI_DEVICE_ERROR;
3472 }
3473
3474 Status = CheckTargetStatus (TargetStatus);
3475 if (Status == EFI_NOT_READY) {
3476 //
3477 // reset the scsi device
3478 //
3479 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3480 *NeedRetry = TRUE;
3481 return EFI_DEVICE_ERROR;
3482 } else if (Status == EFI_DEVICE_ERROR) {
3483 *NeedRetry = FALSE;
3484 return EFI_DEVICE_ERROR;
3485 }
3486
3487 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3488 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
3489 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3490 if (Action == ACTION_RETRY_COMMAND_LATER) {
3491 *NeedRetry = TRUE;
3492 return EFI_DEVICE_ERROR;
3493 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3494 if (SectorCount <= 1) {
3495 //
3496 // Jump out if the operation still fails with one sector transfer length.
3497 //
3498 *NeedRetry = FALSE;
3499 return EFI_DEVICE_ERROR;
3500 }
3501 //
3502 // Try again with half length if the sense data shows we need to retry.
3503 //
3504 SectorCount >>= 1;
3505 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3506 goto BackOff;
3507 } else {
3508 *NeedRetry = FALSE;
3509 return EFI_DEVICE_ERROR;
3510 }
3511 }
3512
3513 return ReturnStatus;
3514 }
3515
3516
3517 /**
3518 Internal helper notify function in which determine whether retry of a SCSI
3519 Read/Write command is needed and signal the event passed from Block I/O(2) if
3520 the SCSI I/O operation completes.
3521
3522 @param Event The instance of EFI_EVENT.
3523 @param Context The parameter passed in.
3524
3525 **/
3526 VOID
3527 EFIAPI
3528 ScsiDiskNotify (
3529 IN EFI_EVENT Event,
3530 IN VOID *Context
3531 )
3532 {
3533 EFI_STATUS Status;
3534 SCSI_ASYNC_RW_REQUEST *Request;
3535 SCSI_DISK_DEV *ScsiDiskDevice;
3536 EFI_BLOCK_IO2_TOKEN *Token;
3537 UINTN Action;
3538 UINT32 OldDataLength;
3539 UINT32 OldSectorCount;
3540 UINT8 MaxRetry;
3541
3542 gBS->CloseEvent (Event);
3543
3544 Request = (SCSI_ASYNC_RW_REQUEST *) Context;
3545 ScsiDiskDevice = Request->ScsiDiskDevice;
3546 Token = Request->BlkIo2Req->Token;
3547 OldDataLength = Request->DataLength;
3548 OldSectorCount = Request->SectorCount;
3549 MaxRetry = 2;
3550
3551 //
3552 // If previous sub-tasks already fails, no need to process this sub-task.
3553 //
3554 if (Token->TransactionStatus != EFI_SUCCESS) {
3555 goto Exit;
3556 }
3557
3558 //
3559 // Check HostAdapterStatus and TargetStatus
3560 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3561 //
3562 Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
3563 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3564 if (++Request->TimesRetry > MaxRetry) {
3565 Token->TransactionStatus = EFI_DEVICE_ERROR;
3566 goto Exit;
3567 } else {
3568 goto Retry;
3569 }
3570 } else if (Status == EFI_DEVICE_ERROR) {
3571 //
3572 // reset the scsi channel
3573 //
3574 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3575 Token->TransactionStatus = EFI_DEVICE_ERROR;
3576 goto Exit;
3577 }
3578
3579 Status = CheckTargetStatus (Request->TargetStatus);
3580 if (Status == EFI_NOT_READY) {
3581 //
3582 // reset the scsi device
3583 //
3584 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3585 if (++Request->TimesRetry > MaxRetry) {
3586 Token->TransactionStatus = EFI_DEVICE_ERROR;
3587 goto Exit;
3588 } else {
3589 goto Retry;
3590 }
3591 } else if (Status == EFI_DEVICE_ERROR) {
3592 Token->TransactionStatus = EFI_DEVICE_ERROR;
3593 goto Exit;
3594 }
3595
3596 if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
3597 DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
3598
3599 Status = DetectMediaParsingSenseKeys (
3600 ScsiDiskDevice,
3601 Request->SenseData,
3602 Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
3603 &Action
3604 );
3605 if (Action == ACTION_RETRY_COMMAND_LATER) {
3606 if (++Request->TimesRetry > MaxRetry) {
3607 Token->TransactionStatus = EFI_DEVICE_ERROR;
3608 goto Exit;
3609 } else {
3610 goto Retry;
3611 }
3612 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3613 if (Request->SectorCount <= 1) {
3614 //
3615 // Jump out if the operation still fails with one sector transfer
3616 // length.
3617 //
3618 Token->TransactionStatus = EFI_DEVICE_ERROR;
3619 goto Exit;
3620 }
3621 //
3622 // Try again with two half length request if the sense data shows we need
3623 // to retry.
3624 //
3625 Request->SectorCount >>= 1;
3626 Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3627 Request->TimesRetry = 0;
3628
3629 goto Retry;
3630 } else {
3631 Token->TransactionStatus = EFI_DEVICE_ERROR;
3632 goto Exit;
3633 }
3634 }
3635
3636 //
3637 // This sub-task succeeds, no need to retry.
3638 //
3639 goto Exit;
3640
3641 Retry:
3642 if (Request->InBuffer != NULL) {
3643 //
3644 // SCSI read command
3645 //
3646 if (!ScsiDiskDevice->Cdb16Byte) {
3647 Status = ScsiDiskAsyncRead10 (
3648 ScsiDiskDevice,
3649 Request->Timeout,
3650 Request->TimesRetry,
3651 Request->InBuffer,
3652 Request->DataLength,
3653 (UINT32) Request->StartLba,
3654 Request->SectorCount,
3655 Request->BlkIo2Req,
3656 Token
3657 );
3658 } else {
3659 Status = ScsiDiskAsyncRead16 (
3660 ScsiDiskDevice,
3661 Request->Timeout,
3662 Request->TimesRetry,
3663 Request->InBuffer,
3664 Request->DataLength,
3665 Request->StartLba,
3666 Request->SectorCount,
3667 Request->BlkIo2Req,
3668 Token
3669 );
3670 }
3671
3672 if (EFI_ERROR (Status)) {
3673 Token->TransactionStatus = EFI_DEVICE_ERROR;
3674 goto Exit;
3675 } else if (OldSectorCount != Request->SectorCount) {
3676 //
3677 // Original sub-task will be split into two new sub-tasks with smaller
3678 // DataLength
3679 //
3680 if (!ScsiDiskDevice->Cdb16Byte) {
3681 Status = ScsiDiskAsyncRead10 (
3682 ScsiDiskDevice,
3683 Request->Timeout,
3684 0,
3685 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3686 OldDataLength - Request->DataLength,
3687 (UINT32) Request->StartLba + Request->SectorCount,
3688 OldSectorCount - Request->SectorCount,
3689 Request->BlkIo2Req,
3690 Token
3691 );
3692 } else {
3693 Status = ScsiDiskAsyncRead16 (
3694 ScsiDiskDevice,
3695 Request->Timeout,
3696 0,
3697 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3698 OldDataLength - Request->DataLength,
3699 Request->StartLba + Request->SectorCount,
3700 OldSectorCount - Request->SectorCount,
3701 Request->BlkIo2Req,
3702 Token
3703 );
3704 }
3705 if (EFI_ERROR (Status)) {
3706 Token->TransactionStatus = EFI_DEVICE_ERROR;
3707 goto Exit;
3708 }
3709 }
3710 } else {
3711 //
3712 // SCSI write command
3713 //
3714 if (!ScsiDiskDevice->Cdb16Byte) {
3715 Status = ScsiDiskAsyncWrite10 (
3716 ScsiDiskDevice,
3717 Request->Timeout,
3718 Request->TimesRetry,
3719 Request->OutBuffer,
3720 Request->DataLength,
3721 (UINT32) Request->StartLba,
3722 Request->SectorCount,
3723 Request->BlkIo2Req,
3724 Token
3725 );
3726 } else {
3727 Status = ScsiDiskAsyncWrite16 (
3728 ScsiDiskDevice,
3729 Request->Timeout,
3730 Request->TimesRetry,
3731 Request->OutBuffer,
3732 Request->DataLength,
3733 Request->StartLba,
3734 Request->SectorCount,
3735 Request->BlkIo2Req,
3736 Token
3737 );
3738 }
3739
3740 if (EFI_ERROR (Status)) {
3741 Token->TransactionStatus = EFI_DEVICE_ERROR;
3742 goto Exit;
3743 } else if (OldSectorCount != Request->SectorCount) {
3744 //
3745 // Original sub-task will be split into two new sub-tasks with smaller
3746 // DataLength
3747 //
3748 if (!ScsiDiskDevice->Cdb16Byte) {
3749 Status = ScsiDiskAsyncWrite10 (
3750 ScsiDiskDevice,
3751 Request->Timeout,
3752 0,
3753 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3754 OldDataLength - Request->DataLength,
3755 (UINT32) Request->StartLba + Request->SectorCount,
3756 OldSectorCount - Request->SectorCount,
3757 Request->BlkIo2Req,
3758 Token
3759 );
3760 } else {
3761 Status = ScsiDiskAsyncWrite16 (
3762 ScsiDiskDevice,
3763 Request->Timeout,
3764 0,
3765 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3766 OldDataLength - Request->DataLength,
3767 Request->StartLba + Request->SectorCount,
3768 OldSectorCount - Request->SectorCount,
3769 Request->BlkIo2Req,
3770 Token
3771 );
3772 }
3773 if (EFI_ERROR (Status)) {
3774 Token->TransactionStatus = EFI_DEVICE_ERROR;
3775 goto Exit;
3776 }
3777 }
3778 }
3779
3780 Exit:
3781 RemoveEntryList (&Request->Link);
3782 if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
3783 (Request->BlkIo2Req->LastScsiRW)) {
3784 //
3785 // The last SCSI R/W command of a BlockIo2 request completes
3786 //
3787 RemoveEntryList (&Request->BlkIo2Req->Link);
3788 FreePool (Request->BlkIo2Req); // Should be freed only once
3789 gBS->SignalEvent (Token->Event);
3790 }
3791
3792 FreePool (Request->SenseData);
3793 FreePool (Request);
3794 }
3795
3796
3797 /**
3798 Submit Async Read(10) command.
3799
3800 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3801 @param Timeout The time to complete the command.
3802 @param TimesRetry The number of times the command has been retried.
3803 @param DataBuffer The buffer to fill with the read out data.
3804 @param DataLength The length of buffer.
3805 @param StartLba The start logic block address.
3806 @param SectorCount The number of blocks to read.
3807 @param BlkIo2Req The upstream BlockIo2 request.
3808 @param Token The pointer to the token associated with the
3809 non-blocking read request.
3810
3811 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3812 lack of resources.
3813 @return others Status returned by calling
3814 ScsiRead10CommandEx().
3815
3816 **/
3817 EFI_STATUS
3818 ScsiDiskAsyncRead10 (
3819 IN SCSI_DISK_DEV *ScsiDiskDevice,
3820 IN UINT64 Timeout,
3821 IN UINT8 TimesRetry,
3822 OUT UINT8 *DataBuffer,
3823 IN UINT32 DataLength,
3824 IN UINT32 StartLba,
3825 IN UINT32 SectorCount,
3826 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
3827 IN EFI_BLOCK_IO2_TOKEN *Token
3828 )
3829 {
3830 EFI_STATUS Status;
3831 SCSI_ASYNC_RW_REQUEST *Request;
3832 EFI_EVENT AsyncIoEvent;
3833 EFI_TPL OldTpl;
3834
3835 AsyncIoEvent = NULL;
3836
3837 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
3838 if (Request == NULL) {
3839 return EFI_OUT_OF_RESOURCES;
3840 }
3841
3842 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3843 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
3844 gBS->RestoreTPL (OldTpl);
3845
3846 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
3847 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
3848 if (Request->SenseData == NULL) {
3849 Status = EFI_OUT_OF_RESOURCES;
3850 goto ErrorExit;
3851 }
3852
3853 Request->ScsiDiskDevice = ScsiDiskDevice;
3854 Request->Timeout = Timeout;
3855 Request->TimesRetry = TimesRetry;
3856 Request->InBuffer = DataBuffer;
3857 Request->DataLength = DataLength;
3858 Request->StartLba = StartLba;
3859 Request->SectorCount = SectorCount;
3860 Request->BlkIo2Req = BlkIo2Req;
3861
3862 //
3863 // Create Event
3864 //
3865 Status = gBS->CreateEvent (
3866 EVT_NOTIFY_SIGNAL,
3867 TPL_NOTIFY,
3868 ScsiDiskNotify,
3869 Request,
3870 &AsyncIoEvent
3871 );
3872 if (EFI_ERROR(Status)) {
3873 goto ErrorExit;
3874 }
3875
3876 Status = ScsiRead10CommandEx (
3877 ScsiDiskDevice->ScsiIo,
3878 Request->Timeout,
3879 Request->SenseData,
3880 &Request->SenseDataLength,
3881 &Request->HostAdapterStatus,
3882 &Request->TargetStatus,
3883 Request->InBuffer,
3884 &Request->DataLength,
3885 (UINT32) Request->StartLba,
3886 Request->SectorCount,
3887 AsyncIoEvent
3888 );
3889 if (EFI_ERROR(Status)) {
3890 goto ErrorExit;
3891 }
3892
3893 return EFI_SUCCESS;
3894
3895 ErrorExit:
3896 if (AsyncIoEvent != NULL) {
3897 gBS->CloseEvent (AsyncIoEvent);
3898 }
3899
3900 if (Request != NULL) {
3901 if (Request->SenseData != NULL) {
3902 FreePool (Request->SenseData);
3903 }
3904
3905 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3906 RemoveEntryList (&Request->Link);
3907 gBS->RestoreTPL (OldTpl);
3908
3909 FreePool (Request);
3910 }
3911
3912 return Status;
3913 }
3914
3915
3916 /**
3917 Submit Async Write(10) command.
3918
3919 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3920 @param Timeout The time to complete the command.
3921 @param TimesRetry The number of times the command has been retried.
3922 @param DataBuffer The buffer contains the data to write.
3923 @param DataLength The length of buffer.
3924 @param StartLba The start logic block address.
3925 @param SectorCount The number of blocks to write.
3926 @param BlkIo2Req The upstream BlockIo2 request.
3927 @param Token The pointer to the token associated with the
3928 non-blocking read request.
3929
3930 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3931 lack of resources.
3932 @return others Status returned by calling
3933 ScsiWrite10CommandEx().
3934
3935 **/
3936 EFI_STATUS
3937 ScsiDiskAsyncWrite10 (
3938 IN SCSI_DISK_DEV *ScsiDiskDevice,
3939 IN UINT64 Timeout,
3940 IN UINT8 TimesRetry,
3941 IN UINT8 *DataBuffer,
3942 IN UINT32 DataLength,
3943 IN UINT32 StartLba,
3944 IN UINT32 SectorCount,
3945 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
3946 IN EFI_BLOCK_IO2_TOKEN *Token
3947 )
3948 {
3949 EFI_STATUS Status;
3950 SCSI_ASYNC_RW_REQUEST *Request;
3951 EFI_EVENT AsyncIoEvent;
3952 EFI_TPL OldTpl;
3953
3954 AsyncIoEvent = NULL;
3955
3956 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
3957 if (Request == NULL) {
3958 return EFI_OUT_OF_RESOURCES;
3959 }
3960
3961 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3962 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
3963 gBS->RestoreTPL (OldTpl);
3964
3965 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
3966 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
3967 if (Request->SenseData == NULL) {
3968 Status = EFI_OUT_OF_RESOURCES;
3969 goto ErrorExit;
3970 }
3971
3972 Request->ScsiDiskDevice = ScsiDiskDevice;
3973 Request->Timeout = Timeout;
3974 Request->TimesRetry = TimesRetry;
3975 Request->OutBuffer = DataBuffer;
3976 Request->DataLength = DataLength;
3977 Request->StartLba = StartLba;
3978 Request->SectorCount = SectorCount;
3979 Request->BlkIo2Req = BlkIo2Req;
3980
3981 //
3982 // Create Event
3983 //
3984 Status = gBS->CreateEvent (
3985 EVT_NOTIFY_SIGNAL,
3986 TPL_NOTIFY,
3987 ScsiDiskNotify,
3988 Request,
3989 &AsyncIoEvent
3990 );
3991 if (EFI_ERROR(Status)) {
3992 goto ErrorExit;
3993 }
3994
3995 Status = ScsiWrite10CommandEx (
3996 ScsiDiskDevice->ScsiIo,
3997 Request->Timeout,
3998 Request->SenseData,
3999 &Request->SenseDataLength,
4000 &Request->HostAdapterStatus,
4001 &Request->TargetStatus,
4002 Request->OutBuffer,
4003 &Request->DataLength,
4004 (UINT32) Request->StartLba,
4005 Request->SectorCount,
4006 AsyncIoEvent
4007 );
4008 if (EFI_ERROR(Status)) {
4009 goto ErrorExit;
4010 }
4011
4012 return EFI_SUCCESS;
4013
4014 ErrorExit:
4015 if (AsyncIoEvent != NULL) {
4016 gBS->CloseEvent (AsyncIoEvent);
4017 }
4018
4019 if (Request != NULL) {
4020 if (Request->SenseData != NULL) {
4021 FreePool (Request->SenseData);
4022 }
4023
4024 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4025 RemoveEntryList (&Request->Link);
4026 gBS->RestoreTPL (OldTpl);
4027
4028 FreePool (Request);
4029 }
4030
4031 return Status;
4032 }
4033
4034
4035 /**
4036 Submit Async Read(16) command.
4037
4038 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4039 @param Timeout The time to complete the command.
4040 @param TimesRetry The number of times the command has been retried.
4041 @param DataBuffer The buffer to fill with the read out data.
4042 @param DataLength The length of buffer.
4043 @param StartLba The start logic block address.
4044 @param SectorCount The number of blocks to read.
4045 @param BlkIo2Req The upstream BlockIo2 request.
4046 @param Token The pointer to the token associated with the
4047 non-blocking read request.
4048
4049 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4050 lack of resources.
4051 @return others Status returned by calling
4052 ScsiRead16CommandEx().
4053
4054 **/
4055 EFI_STATUS
4056 ScsiDiskAsyncRead16 (
4057 IN SCSI_DISK_DEV *ScsiDiskDevice,
4058 IN UINT64 Timeout,
4059 IN UINT8 TimesRetry,
4060 OUT UINT8 *DataBuffer,
4061 IN UINT32 DataLength,
4062 IN UINT64 StartLba,
4063 IN UINT32 SectorCount,
4064 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
4065 IN EFI_BLOCK_IO2_TOKEN *Token
4066 )
4067 {
4068 EFI_STATUS Status;
4069 SCSI_ASYNC_RW_REQUEST *Request;
4070 EFI_EVENT AsyncIoEvent;
4071 EFI_TPL OldTpl;
4072
4073 AsyncIoEvent = NULL;
4074
4075 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4076 if (Request == NULL) {
4077 return EFI_OUT_OF_RESOURCES;
4078 }
4079
4080 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4081 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4082 gBS->RestoreTPL (OldTpl);
4083
4084 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4085 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
4086 if (Request->SenseData == NULL) {
4087 Status = EFI_OUT_OF_RESOURCES;
4088 goto ErrorExit;
4089 }
4090
4091 Request->ScsiDiskDevice = ScsiDiskDevice;
4092 Request->Timeout = Timeout;
4093 Request->TimesRetry = TimesRetry;
4094 Request->InBuffer = DataBuffer;
4095 Request->DataLength = DataLength;
4096 Request->StartLba = StartLba;
4097 Request->SectorCount = SectorCount;
4098 Request->BlkIo2Req = BlkIo2Req;
4099
4100 //
4101 // Create Event
4102 //
4103 Status = gBS->CreateEvent (
4104 EVT_NOTIFY_SIGNAL,
4105 TPL_NOTIFY,
4106 ScsiDiskNotify,
4107 Request,
4108 &AsyncIoEvent
4109 );
4110 if (EFI_ERROR(Status)) {
4111 goto ErrorExit;
4112 }
4113
4114 Status = ScsiRead16CommandEx (
4115 ScsiDiskDevice->ScsiIo,
4116 Request->Timeout,
4117 Request->SenseData,
4118 &Request->SenseDataLength,
4119 &Request->HostAdapterStatus,
4120 &Request->TargetStatus,
4121 Request->InBuffer,
4122 &Request->DataLength,
4123 Request->StartLba,
4124 Request->SectorCount,
4125 AsyncIoEvent
4126 );
4127 if (EFI_ERROR(Status)) {
4128 goto ErrorExit;
4129 }
4130
4131 return EFI_SUCCESS;
4132
4133 ErrorExit:
4134 if (AsyncIoEvent != NULL) {
4135 gBS->CloseEvent (AsyncIoEvent);
4136 }
4137
4138 if (Request != NULL) {
4139 if (Request->SenseData != NULL) {
4140 FreePool (Request->SenseData);
4141 }
4142
4143 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4144 RemoveEntryList (&Request->Link);
4145 gBS->RestoreTPL (OldTpl);
4146
4147 FreePool (Request);
4148 }
4149
4150 return Status;
4151 }
4152
4153
4154 /**
4155 Submit Async Write(16) command.
4156
4157 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4158 @param Timeout The time to complete the command.
4159 @param TimesRetry The number of times the command has been retried.
4160 @param DataBuffer The buffer contains the data to write.
4161 @param DataLength The length of buffer.
4162 @param StartLba The start logic block address.
4163 @param SectorCount The number of blocks to write.
4164 @param BlkIo2Req The upstream BlockIo2 request.
4165 @param Token The pointer to the token associated with the
4166 non-blocking read request.
4167
4168 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4169 lack of resources.
4170 @return others Status returned by calling
4171 ScsiWrite16CommandEx().
4172
4173 **/
4174 EFI_STATUS
4175 ScsiDiskAsyncWrite16 (
4176 IN SCSI_DISK_DEV *ScsiDiskDevice,
4177 IN UINT64 Timeout,
4178 IN UINT8 TimesRetry,
4179 IN UINT8 *DataBuffer,
4180 IN UINT32 DataLength,
4181 IN UINT64 StartLba,
4182 IN UINT32 SectorCount,
4183 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
4184 IN EFI_BLOCK_IO2_TOKEN *Token
4185 )
4186 {
4187 EFI_STATUS Status;
4188 SCSI_ASYNC_RW_REQUEST *Request;
4189 EFI_EVENT AsyncIoEvent;
4190 EFI_TPL OldTpl;
4191
4192 AsyncIoEvent = NULL;
4193
4194 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4195 if (Request == NULL) {
4196 return EFI_OUT_OF_RESOURCES;
4197 }
4198
4199 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4200 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4201 gBS->RestoreTPL (OldTpl);
4202
4203 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4204 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
4205 if (Request->SenseData == NULL) {
4206 Status = EFI_OUT_OF_RESOURCES;
4207 goto ErrorExit;
4208 }
4209
4210 Request->ScsiDiskDevice = ScsiDiskDevice;
4211 Request->Timeout = Timeout;
4212 Request->TimesRetry = TimesRetry;
4213 Request->OutBuffer = DataBuffer;
4214 Request->DataLength = DataLength;
4215 Request->StartLba = StartLba;
4216 Request->SectorCount = SectorCount;
4217 Request->BlkIo2Req = BlkIo2Req;
4218
4219 //
4220 // Create Event
4221 //
4222 Status = gBS->CreateEvent (
4223 EVT_NOTIFY_SIGNAL,
4224 TPL_NOTIFY,
4225 ScsiDiskNotify,
4226 Request,
4227 &AsyncIoEvent
4228 );
4229 if (EFI_ERROR(Status)) {
4230 goto ErrorExit;
4231 }
4232
4233 Status = ScsiWrite16CommandEx (
4234 ScsiDiskDevice->ScsiIo,
4235 Request->Timeout,
4236 Request->SenseData,
4237 &Request->SenseDataLength,
4238 &Request->HostAdapterStatus,
4239 &Request->TargetStatus,
4240 Request->OutBuffer,
4241 &Request->DataLength,
4242 Request->StartLba,
4243 Request->SectorCount,
4244 AsyncIoEvent
4245 );
4246 if (EFI_ERROR(Status)) {
4247 goto ErrorExit;
4248 }
4249
4250 return EFI_SUCCESS;
4251
4252 ErrorExit:
4253 if (AsyncIoEvent != NULL) {
4254 gBS->CloseEvent (AsyncIoEvent);
4255 }
4256
4257 if (Request != NULL) {
4258 if (Request->SenseData != NULL) {
4259 FreePool (Request->SenseData);
4260 }
4261
4262 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4263 RemoveEntryList (&Request->Link);
4264 gBS->RestoreTPL (OldTpl);
4265
4266 FreePool (Request);
4267 }
4268
4269 return Status;
4270 }
4271
4272
4273 /**
4274 Check sense key to find if media presents.
4275
4276 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4277 @param SenseCounts The number of sense key
4278
4279 @retval TRUE NOT any media
4280 @retval FALSE Media presents
4281 **/
4282 BOOLEAN
4283 ScsiDiskIsNoMedia (
4284 IN EFI_SCSI_SENSE_DATA *SenseData,
4285 IN UINTN SenseCounts
4286 )
4287 {
4288 EFI_SCSI_SENSE_DATA *SensePtr;
4289 UINTN Index;
4290 BOOLEAN IsNoMedia;
4291
4292 IsNoMedia = FALSE;
4293 SensePtr = SenseData;
4294
4295 for (Index = 0; Index < SenseCounts; Index++) {
4296 //
4297 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4298 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4299 //
4300 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
4301 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
4302 IsNoMedia = TRUE;
4303 }
4304 SensePtr++;
4305 }
4306
4307 return IsNoMedia;
4308 }
4309
4310
4311 /**
4312 Parse sense key.
4313
4314 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4315 @param SenseCounts The number of sense key
4316
4317 @retval TRUE Error
4318 @retval FALSE NOT error
4319
4320 **/
4321 BOOLEAN
4322 ScsiDiskIsMediaError (
4323 IN EFI_SCSI_SENSE_DATA *SenseData,
4324 IN UINTN SenseCounts
4325 )
4326 {
4327 EFI_SCSI_SENSE_DATA *SensePtr;
4328 UINTN Index;
4329 BOOLEAN IsError;
4330
4331 IsError = FALSE;
4332 SensePtr = SenseData;
4333
4334 for (Index = 0; Index < SenseCounts; Index++) {
4335
4336 switch (SensePtr->Sense_Key) {
4337
4338 case EFI_SCSI_SK_MEDIUM_ERROR:
4339 //
4340 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4341 //
4342 switch (SensePtr->Addnl_Sense_Code) {
4343
4344 //
4345 // fall through
4346 //
4347 case EFI_SCSI_ASC_MEDIA_ERR1:
4348
4349 //
4350 // fall through
4351 //
4352 case EFI_SCSI_ASC_MEDIA_ERR2:
4353
4354 //
4355 // fall through
4356 //
4357 case EFI_SCSI_ASC_MEDIA_ERR3:
4358 case EFI_SCSI_ASC_MEDIA_ERR4:
4359 IsError = TRUE;
4360 break;
4361
4362 default:
4363 break;
4364 }
4365
4366 break;
4367
4368 case EFI_SCSI_SK_NOT_READY:
4369 //
4370 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4371 //
4372 switch (SensePtr->Addnl_Sense_Code) {
4373 //
4374 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4375 //
4376 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
4377 IsError = TRUE;
4378 break;
4379
4380 default:
4381 break;
4382 }
4383 break;
4384
4385 default:
4386 break;
4387 }
4388
4389 SensePtr++;
4390 }
4391
4392 return IsError;
4393 }
4394
4395
4396 /**
4397 Check sense key to find if hardware error happens.
4398
4399 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4400 @param SenseCounts The number of sense key
4401
4402 @retval TRUE Hardware error exits.
4403 @retval FALSE NO error.
4404
4405 **/
4406 BOOLEAN
4407 ScsiDiskIsHardwareError (
4408 IN EFI_SCSI_SENSE_DATA *SenseData,
4409 IN UINTN SenseCounts
4410 )
4411 {
4412 EFI_SCSI_SENSE_DATA *SensePtr;
4413 UINTN Index;
4414 BOOLEAN IsError;
4415
4416 IsError = FALSE;
4417 SensePtr = SenseData;
4418
4419 for (Index = 0; Index < SenseCounts; Index++) {
4420
4421 //
4422 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4423 //
4424 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
4425 IsError = TRUE;
4426 }
4427
4428 SensePtr++;
4429 }
4430
4431 return IsError;
4432 }
4433
4434
4435 /**
4436 Check sense key to find if media has changed.
4437
4438 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4439 @param SenseCounts The number of sense key
4440
4441 @retval TRUE Media is changed.
4442 @retval FALSE Media is NOT changed.
4443 **/
4444 BOOLEAN
4445 ScsiDiskIsMediaChange (
4446 IN EFI_SCSI_SENSE_DATA *SenseData,
4447 IN UINTN SenseCounts
4448 )
4449 {
4450 EFI_SCSI_SENSE_DATA *SensePtr;
4451 UINTN Index;
4452 BOOLEAN IsMediaChanged;
4453
4454 IsMediaChanged = FALSE;
4455 SensePtr = SenseData;
4456
4457 for (Index = 0; Index < SenseCounts; Index++) {
4458 //
4459 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4460 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4461 //
4462 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
4463 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
4464 IsMediaChanged = TRUE;
4465 }
4466
4467 SensePtr++;
4468 }
4469
4470 return IsMediaChanged;
4471 }
4472
4473 /**
4474 Check sense key to find if reset happens.
4475
4476 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4477 @param SenseCounts The number of sense key
4478
4479 @retval TRUE It is reset before.
4480 @retval FALSE It is NOT reset before.
4481
4482 **/
4483 BOOLEAN
4484 ScsiDiskIsResetBefore (
4485 IN EFI_SCSI_SENSE_DATA *SenseData,
4486 IN UINTN SenseCounts
4487 )
4488 {
4489 EFI_SCSI_SENSE_DATA *SensePtr;
4490 UINTN Index;
4491 BOOLEAN IsResetBefore;
4492
4493 IsResetBefore = FALSE;
4494 SensePtr = SenseData;
4495
4496 for (Index = 0; Index < SenseCounts; Index++) {
4497
4498 //
4499 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4500 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4501 //
4502 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
4503 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
4504 IsResetBefore = TRUE;
4505 }
4506
4507 SensePtr++;
4508 }
4509
4510 return IsResetBefore;
4511 }
4512
4513 /**
4514 Check sense key to find if the drive is ready.
4515
4516 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4517 @param SenseCounts The number of sense key
4518 @param RetryLater The flag means if need a retry
4519
4520 @retval TRUE Drive is ready.
4521 @retval FALSE Drive is NOT ready.
4522
4523 **/
4524 BOOLEAN
4525 ScsiDiskIsDriveReady (
4526 IN EFI_SCSI_SENSE_DATA *SenseData,
4527 IN UINTN SenseCounts,
4528 OUT BOOLEAN *RetryLater
4529 )
4530 {
4531 EFI_SCSI_SENSE_DATA *SensePtr;
4532 UINTN Index;
4533 BOOLEAN IsReady;
4534
4535 IsReady = TRUE;
4536 *RetryLater = FALSE;
4537 SensePtr = SenseData;
4538
4539 for (Index = 0; Index < SenseCounts; Index++) {
4540
4541 switch (SensePtr->Sense_Key) {
4542
4543 case EFI_SCSI_SK_NOT_READY:
4544 //
4545 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4546 //
4547 switch (SensePtr->Addnl_Sense_Code) {
4548 case EFI_SCSI_ASC_NOT_READY:
4549 //
4550 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4551 //
4552 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
4553 case EFI_SCSI_ASCQ_IN_PROGRESS:
4554 //
4555 // Additional Sense Code Qualifier is
4556 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4557 //
4558 IsReady = FALSE;
4559 *RetryLater = TRUE;
4560 break;
4561
4562 default:
4563 IsReady = FALSE;
4564 *RetryLater = FALSE;
4565 break;
4566 }
4567 break;
4568
4569 default:
4570 break;
4571 }
4572 break;
4573
4574 default:
4575 break;
4576 }
4577
4578 SensePtr++;
4579 }
4580
4581 return IsReady;
4582 }
4583
4584 /**
4585 Check sense key to find if it has sense key.
4586
4587 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4588 @param SenseCounts - The number of sense key
4589
4590 @retval TRUE It has sense key.
4591 @retval FALSE It has NOT any sense key.
4592
4593 **/
4594 BOOLEAN
4595 ScsiDiskHaveSenseKey (
4596 IN EFI_SCSI_SENSE_DATA *SenseData,
4597 IN UINTN SenseCounts
4598 )
4599 {
4600 EFI_SCSI_SENSE_DATA *SensePtr;
4601 UINTN Index;
4602 BOOLEAN HaveSenseKey;
4603
4604 if (SenseCounts == 0) {
4605 HaveSenseKey = FALSE;
4606 } else {
4607 HaveSenseKey = TRUE;
4608 }
4609
4610 SensePtr = SenseData;
4611
4612 for (Index = 0; Index < SenseCounts; Index++) {
4613
4614 //
4615 // Sense Key is SK_NO_SENSE (0x0)
4616 //
4617 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
4618 (Index == 0)) {
4619 HaveSenseKey = FALSE;
4620 }
4621
4622 SensePtr++;
4623 }
4624
4625 return HaveSenseKey;
4626 }
4627
4628 /**
4629 Release resource about disk device.
4630
4631 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4632
4633 **/
4634 VOID
4635 ReleaseScsiDiskDeviceResources (
4636 IN SCSI_DISK_DEV *ScsiDiskDevice
4637 )
4638 {
4639 if (ScsiDiskDevice == NULL) {
4640 return ;
4641 }
4642
4643 if (ScsiDiskDevice->SenseData != NULL) {
4644 FreePool (ScsiDiskDevice->SenseData);
4645 ScsiDiskDevice->SenseData = NULL;
4646 }
4647
4648 if (ScsiDiskDevice->ControllerNameTable != NULL) {
4649 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
4650 ScsiDiskDevice->ControllerNameTable = NULL;
4651 }
4652
4653 FreePool (ScsiDiskDevice);
4654
4655 ScsiDiskDevice = NULL;
4656 }
4657
4658 /**
4659 Determine if Block Io & Block Io2 should be produced.
4660
4661
4662 @param ChildHandle Child Handle to retrieve Parent information.
4663
4664 @retval TRUE Should produce Block Io & Block Io2.
4665 @retval FALSE Should not produce Block Io & Block Io2.
4666
4667 **/
4668 BOOLEAN
4669 DetermineInstallBlockIo (
4670 IN EFI_HANDLE ChildHandle
4671 )
4672 {
4673 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
4674 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
4675
4676 //
4677 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4678 // check its attribute, logic or physical.
4679 //
4680 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
4681 if (ExtScsiPassThru != NULL) {
4682 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
4683 return TRUE;
4684 }
4685 }
4686
4687 //
4688 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4689 // check its attribute, logic or physical.
4690 //
4691 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
4692 if (ScsiPassThru != NULL) {
4693 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
4694 return TRUE;
4695 }
4696 }
4697
4698 return FALSE;
4699 }
4700
4701 /**
4702 Search protocol database and check to see if the protocol
4703 specified by ProtocolGuid is present on a ControllerHandle and opened by
4704 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4705 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4706 will be opened on it.
4707
4708
4709 @param ProtocolGuid ProtocolGuid pointer.
4710 @param ChildHandle Child Handle to retrieve Parent information.
4711
4712 **/
4713 VOID *
4714 EFIAPI
4715 GetParentProtocol (
4716 IN EFI_GUID *ProtocolGuid,
4717 IN EFI_HANDLE ChildHandle
4718 )
4719 {
4720 UINTN Index;
4721 UINTN HandleCount;
4722 VOID *Interface;
4723 EFI_STATUS Status;
4724 EFI_HANDLE *HandleBuffer;
4725
4726 //
4727 // Retrieve the list of all handles from the handle database
4728 //
4729 Status = gBS->LocateHandleBuffer (
4730 ByProtocol,
4731 ProtocolGuid,
4732 NULL,
4733 &HandleCount,
4734 &HandleBuffer
4735 );
4736
4737 if (EFI_ERROR (Status)) {
4738 return NULL;
4739 }
4740
4741 //
4742 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4743 //
4744 for (Index = 0; Index < HandleCount; Index++) {
4745 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
4746 if (!EFI_ERROR (Status)) {
4747 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
4748 if (!EFI_ERROR (Status)) {
4749 gBS->FreePool (HandleBuffer);
4750 return Interface;
4751 }
4752 }
4753 }
4754
4755 gBS->FreePool (HandleBuffer);
4756 return NULL;
4757 }
4758
4759 /**
4760 Provides inquiry information for the controller type.
4761
4762 This function is used by the IDE bus driver to get inquiry data. Data format
4763 of Identify data is defined by the Interface GUID.
4764
4765 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4766 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4767 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4768
4769 @retval EFI_SUCCESS The command was accepted without any errors.
4770 @retval EFI_NOT_FOUND Device does not support this data class
4771 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4772 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4773
4774 **/
4775 EFI_STATUS
4776 EFIAPI
4777 ScsiDiskInfoInquiry (
4778 IN EFI_DISK_INFO_PROTOCOL *This,
4779 IN OUT VOID *InquiryData,
4780 IN OUT UINT32 *InquiryDataSize
4781 )
4782 {
4783 EFI_STATUS Status;
4784 SCSI_DISK_DEV *ScsiDiskDevice;
4785
4786 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
4787
4788 Status = EFI_BUFFER_TOO_SMALL;
4789 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
4790 Status = EFI_SUCCESS;
4791 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
4792 }
4793 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
4794 return Status;
4795 }
4796
4797
4798 /**
4799 Provides identify information for the controller type.
4800
4801 This function is used by the IDE bus driver to get identify data. Data format
4802 of Identify data is defined by the Interface GUID.
4803
4804 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4805 instance.
4806 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4807 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4808 size.
4809
4810 @retval EFI_SUCCESS The command was accepted without any errors.
4811 @retval EFI_NOT_FOUND Device does not support this data class
4812 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4813 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4814
4815 **/
4816 EFI_STATUS
4817 EFIAPI
4818 ScsiDiskInfoIdentify (
4819 IN EFI_DISK_INFO_PROTOCOL *This,
4820 IN OUT VOID *IdentifyData,
4821 IN OUT UINT32 *IdentifyDataSize
4822 )
4823 {
4824 EFI_STATUS Status;
4825 SCSI_DISK_DEV *ScsiDiskDevice;
4826
4827 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
4828 //
4829 // Physical SCSI bus does not support this data class.
4830 //
4831 return EFI_NOT_FOUND;
4832 }
4833
4834 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
4835
4836 Status = EFI_BUFFER_TOO_SMALL;
4837 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
4838 Status = EFI_SUCCESS;
4839 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
4840 }
4841 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
4842 return Status;
4843 }
4844
4845 /**
4846 Provides sense data information for the controller type.
4847
4848 This function is used by the IDE bus driver to get sense data.
4849 Data format of Sense data is defined by the Interface GUID.
4850
4851 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4852 @param[in, out] SenseData Pointer to the SenseData.
4853 @param[in, out] SenseDataSize Size of SenseData in bytes.
4854 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4855
4856 @retval EFI_SUCCESS The command was accepted without any errors.
4857 @retval EFI_NOT_FOUND Device does not support this data class.
4858 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4859 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4860
4861 **/
4862 EFI_STATUS
4863 EFIAPI
4864 ScsiDiskInfoSenseData (
4865 IN EFI_DISK_INFO_PROTOCOL *This,
4866 IN OUT VOID *SenseData,
4867 IN OUT UINT32 *SenseDataSize,
4868 OUT UINT8 *SenseDataNumber
4869 )
4870 {
4871 return EFI_NOT_FOUND;
4872 }
4873
4874
4875 /**
4876 This function is used by the IDE bus driver to get controller information.
4877
4878 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4879 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4880 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4881
4882 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4883 @retval EFI_UNSUPPORTED This is not an IDE device.
4884
4885 **/
4886 EFI_STATUS
4887 EFIAPI
4888 ScsiDiskInfoWhichIde (
4889 IN EFI_DISK_INFO_PROTOCOL *This,
4890 OUT UINT32 *IdeChannel,
4891 OUT UINT32 *IdeDevice
4892 )
4893 {
4894 SCSI_DISK_DEV *ScsiDiskDevice;
4895
4896 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
4897 //
4898 // This is not an IDE physical device.
4899 //
4900 return EFI_UNSUPPORTED;
4901 }
4902
4903 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
4904 *IdeChannel = ScsiDiskDevice->Channel;
4905 *IdeDevice = ScsiDiskDevice->Device;
4906
4907 return EFI_SUCCESS;
4908 }
4909
4910
4911 /**
4912 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4913
4914 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4915 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4916 via SCSI Request Packet.
4917
4918 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4919
4920 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4921 @retval others Some error occurred during the identification that ATAPI device.
4922
4923 **/
4924 EFI_STATUS
4925 AtapiIdentifyDevice (
4926 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
4927 )
4928 {
4929 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
4930 UINT8 Cdb[6];
4931
4932 //
4933 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4934 //
4935 ZeroMem (&CommandPacket, sizeof (CommandPacket));
4936 ZeroMem (Cdb, sizeof (Cdb));
4937
4938 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
4939 CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
4940 CommandPacket.Cdb = Cdb;
4941 CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
4942 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
4943 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
4944
4945 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
4946 }
4947
4948
4949 /**
4950 Initialize the installation of DiskInfo protocol.
4951
4952 This function prepares for the installation of DiskInfo protocol on the child handle.
4953 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4954 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4955 to be IDE/AHCI interface GUID.
4956
4957 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4958 @param ChildHandle Child handle to install DiskInfo protocol.
4959
4960 **/
4961 VOID
4962 InitializeInstallDiskInfo (
4963 IN SCSI_DISK_DEV *ScsiDiskDevice,
4964 IN EFI_HANDLE ChildHandle
4965 )
4966 {
4967 EFI_STATUS Status;
4968 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
4969 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
4970 ATAPI_DEVICE_PATH *AtapiDevicePath;
4971 SATA_DEVICE_PATH *SataDevicePath;
4972 UINTN IdentifyRetry;
4973
4974 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
4975 //
4976 // Device Path protocol must be installed on the device handle.
4977 //
4978 ASSERT_EFI_ERROR (Status);
4979 //
4980 // Copy the DiskInfo protocol template.
4981 //
4982 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
4983
4984 while (!IsDevicePathEnd (DevicePathNode)) {
4985 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
4986 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
4987 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
4988 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
4989 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
4990 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
4991
4992 IdentifyRetry = 3;
4993 do {
4994 //
4995 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
4996 // with IDE/AHCI interface GUID.
4997 //
4998 Status = AtapiIdentifyDevice (ScsiDiskDevice);
4999 if (!EFI_ERROR (Status)) {
5000 if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
5001 //
5002 // We find the valid ATAPI device path
5003 //
5004 AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
5005 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
5006 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
5007 //
5008 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5009 //
5010 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
5011 } else {
5012 //
5013 // We find the valid SATA device path
5014 //
5015 SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
5016 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
5017 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
5018 //
5019 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5020 //
5021 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
5022 }
5023 return;
5024 }
5025 } while (--IdentifyRetry > 0);
5026 } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
5027 (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) {
5028 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
5029 break;
5030 }
5031 DevicePathNode = ChildDevicePathNode;
5032 }
5033
5034 return;
5035 }