]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
MdeModulePkg: ScsiDiskDxe: adapt SectorCount when shortening transfers
[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 - 2015, 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->Handle = Controller;
243
244 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
245 switch (ScsiDiskDevice->DeviceType) {
246 case EFI_SCSI_TYPE_DISK:
247 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
248 MustReadCapacity = TRUE;
249 break;
250
251 case EFI_SCSI_TYPE_CDROM:
252 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
253 MustReadCapacity = FALSE;
254 break;
255 }
256 //
257 // The Sense Data Array's initial size is 6
258 //
259 ScsiDiskDevice->SenseDataNumber = 6;
260 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (
261 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
262 );
263 if (ScsiDiskDevice->SenseData == NULL) {
264 gBS->CloseProtocol (
265 Controller,
266 &gEfiScsiIoProtocolGuid,
267 This->DriverBindingHandle,
268 Controller
269 );
270 FreePool (ScsiDiskDevice);
271 return EFI_OUT_OF_RESOURCES;
272 }
273
274 //
275 // Retrieve device information
276 //
277 MaxRetry = 2;
278 for (Index = 0; Index < MaxRetry; Index++) {
279 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
280 if (!EFI_ERROR (Status)) {
281 break;
282 }
283
284 if (!NeedRetry) {
285 FreePool (ScsiDiskDevice->SenseData);
286 gBS->CloseProtocol (
287 Controller,
288 &gEfiScsiIoProtocolGuid,
289 This->DriverBindingHandle,
290 Controller
291 );
292 FreePool (ScsiDiskDevice);
293 return EFI_DEVICE_ERROR;
294 }
295 }
296 //
297 // The second parameter "TRUE" means must
298 // retrieve media capacity
299 //
300 Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
301 if (!EFI_ERROR (Status)) {
302 //
303 // Determine if Block IO should be produced on this controller handle
304 //
305 if (DetermineInstallBlockIo(Controller)) {
306 InitializeInstallDiskInfo(ScsiDiskDevice, Controller);
307 Status = gBS->InstallMultipleProtocolInterfaces (
308 &Controller,
309 &gEfiBlockIoProtocolGuid,
310 &ScsiDiskDevice->BlkIo,
311 &gEfiDiskInfoProtocolGuid,
312 &ScsiDiskDevice->DiskInfo,
313 NULL
314 );
315 if (!EFI_ERROR(Status)) {
316 ScsiDiskDevice->ControllerNameTable = NULL;
317 AddUnicodeString2 (
318 "eng",
319 gScsiDiskComponentName.SupportedLanguages,
320 &ScsiDiskDevice->ControllerNameTable,
321 L"SCSI Disk Device",
322 TRUE
323 );
324 AddUnicodeString2 (
325 "en",
326 gScsiDiskComponentName2.SupportedLanguages,
327 &ScsiDiskDevice->ControllerNameTable,
328 L"SCSI Disk Device",
329 FALSE
330 );
331 return EFI_SUCCESS;
332 }
333 }
334 }
335
336 gBS->FreePool (ScsiDiskDevice->SenseData);
337 gBS->FreePool (ScsiDiskDevice);
338 gBS->CloseProtocol (
339 Controller,
340 &gEfiScsiIoProtocolGuid,
341 This->DriverBindingHandle,
342 Controller
343 );
344 return Status;
345
346 }
347
348
349 /**
350 Stop this driver on ControllerHandle.
351
352 This service is called by the EFI boot service DisconnectController().
353 In order to make drivers as small as possible, there are a few calling
354 restrictions for this service. DisconnectController() must follow these
355 calling restrictions. If any other agent wishes to call Stop() it must
356 also follow these calling restrictions.
357
358 @param This Protocol instance pointer.
359 @param ControllerHandle Handle of device to stop driver on
360 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
361 children is zero stop the entire bus driver.
362 @param ChildHandleBuffer List of Child Handles to Stop.
363
364 @retval EFI_SUCCESS This driver is removed ControllerHandle
365 @retval other This driver was not removed from this device
366
367 **/
368 EFI_STATUS
369 EFIAPI
370 ScsiDiskDriverBindingStop (
371 IN EFI_DRIVER_BINDING_PROTOCOL *This,
372 IN EFI_HANDLE Controller,
373 IN UINTN NumberOfChildren,
374 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
375 )
376 {
377 EFI_BLOCK_IO_PROTOCOL *BlkIo;
378 SCSI_DISK_DEV *ScsiDiskDevice;
379 EFI_STATUS Status;
380
381 Status = gBS->OpenProtocol (
382 Controller,
383 &gEfiBlockIoProtocolGuid,
384 (VOID **) &BlkIo,
385 This->DriverBindingHandle,
386 Controller,
387 EFI_OPEN_PROTOCOL_GET_PROTOCOL
388 );
389 if (EFI_ERROR (Status)) {
390 return Status;
391 }
392
393 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);
394 Status = gBS->UninstallMultipleProtocolInterfaces (
395 Controller,
396 &gEfiBlockIoProtocolGuid,
397 &ScsiDiskDevice->BlkIo,
398 &gEfiDiskInfoProtocolGuid,
399 &ScsiDiskDevice->DiskInfo,
400 NULL
401 );
402 if (!EFI_ERROR (Status)) {
403 gBS->CloseProtocol (
404 Controller,
405 &gEfiScsiIoProtocolGuid,
406 This->DriverBindingHandle,
407 Controller
408 );
409
410 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
411
412 return EFI_SUCCESS;
413 }
414 //
415 // errors met
416 //
417 return Status;
418 }
419
420 /**
421 Reset SCSI Disk.
422
423
424 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
425 @param ExtendedVerification The flag about if extend verificate
426
427 @retval EFI_SUCCESS The device was reset.
428 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
429 not be reset.
430 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
431
432 **/
433 EFI_STATUS
434 EFIAPI
435 ScsiDiskReset (
436 IN EFI_BLOCK_IO_PROTOCOL *This,
437 IN BOOLEAN ExtendedVerification
438 )
439 {
440 EFI_TPL OldTpl;
441 SCSI_DISK_DEV *ScsiDiskDevice;
442 EFI_STATUS Status;
443
444 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
445
446 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
447
448 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
449
450 if (EFI_ERROR (Status)) {
451 Status = EFI_DEVICE_ERROR;
452 goto Done;
453 }
454
455 if (!ExtendedVerification) {
456 goto Done;
457 }
458
459 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
460
461 if (EFI_ERROR (Status)) {
462 Status = EFI_DEVICE_ERROR;
463 goto Done;
464 }
465
466 Done:
467 gBS->RestoreTPL (OldTpl);
468 return Status;
469 }
470
471 /**
472 The function is to Read Block from SCSI Disk.
473
474 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
475 @param MediaId The Id of Media detected
476 @param Lba The logic block address
477 @param BufferSize The size of Buffer
478 @param Buffer The buffer to fill the read out data
479
480 @retval EFI_SUCCESS Successfully to read out block.
481 @retval EFI_DEVICE_ERROR Fail to detect media.
482 @retval EFI_NO_MEDIA Media is not present.
483 @retval EFI_MEDIA_CHANGED Media has changed.
484 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
485 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
486
487 **/
488 EFI_STATUS
489 EFIAPI
490 ScsiDiskReadBlocks (
491 IN EFI_BLOCK_IO_PROTOCOL *This,
492 IN UINT32 MediaId,
493 IN EFI_LBA Lba,
494 IN UINTN BufferSize,
495 OUT VOID *Buffer
496 )
497 {
498 SCSI_DISK_DEV *ScsiDiskDevice;
499 EFI_BLOCK_IO_MEDIA *Media;
500 EFI_STATUS Status;
501 UINTN BlockSize;
502 UINTN NumberOfBlocks;
503 BOOLEAN MediaChange;
504 EFI_TPL OldTpl;
505
506 MediaChange = FALSE;
507 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
508 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
509
510 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
511
512 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
513 if (EFI_ERROR (Status)) {
514 Status = EFI_DEVICE_ERROR;
515 goto Done;
516 }
517
518 if (MediaChange) {
519 gBS->ReinstallProtocolInterface (
520 ScsiDiskDevice->Handle,
521 &gEfiBlockIoProtocolGuid,
522 &ScsiDiskDevice->BlkIo,
523 &ScsiDiskDevice->BlkIo
524 );
525 Status = EFI_MEDIA_CHANGED;
526 goto Done;
527 }
528 }
529 //
530 // Get the intrinsic block size
531 //
532 Media = ScsiDiskDevice->BlkIo.Media;
533 BlockSize = Media->BlockSize;
534
535 NumberOfBlocks = BufferSize / BlockSize;
536
537 if (!(Media->MediaPresent)) {
538 Status = EFI_NO_MEDIA;
539 goto Done;
540 }
541
542 if (MediaId != Media->MediaId) {
543 Status = EFI_MEDIA_CHANGED;
544 goto Done;
545 }
546
547 if (Buffer == NULL) {
548 Status = EFI_INVALID_PARAMETER;
549 goto Done;
550 }
551
552 if (BufferSize == 0) {
553 Status = EFI_SUCCESS;
554 goto Done;
555 }
556
557 if (BufferSize % BlockSize != 0) {
558 Status = EFI_BAD_BUFFER_SIZE;
559 goto Done;
560 }
561
562 if (Lba > Media->LastBlock) {
563 Status = EFI_INVALID_PARAMETER;
564 goto Done;
565 }
566
567 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
568 Status = EFI_INVALID_PARAMETER;
569 goto Done;
570 }
571
572 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
573 Status = EFI_INVALID_PARAMETER;
574 goto Done;
575 }
576
577 //
578 // If all the parameters are valid, then perform read sectors command
579 // to transfer data from device to host.
580 //
581 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
582
583 Done:
584 gBS->RestoreTPL (OldTpl);
585 return Status;
586 }
587
588 /**
589 The function is to Write Block to SCSI Disk.
590
591 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
592 @param MediaId The Id of Media detected
593 @param Lba The logic block address
594 @param BufferSize The size of Buffer
595 @param Buffer The buffer to fill the read out data
596
597 @retval EFI_SUCCESS Successfully to read out block.
598 @retval EFI_WRITE_PROTECTED The device can not be written to.
599 @retval EFI_DEVICE_ERROR Fail to detect media.
600 @retval EFI_NO_MEDIA Media is not present.
601 @retval EFI_MEDIA_CHNAGED Media has changed.
602 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
603 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
604
605 **/
606 EFI_STATUS
607 EFIAPI
608 ScsiDiskWriteBlocks (
609 IN EFI_BLOCK_IO_PROTOCOL *This,
610 IN UINT32 MediaId,
611 IN EFI_LBA Lba,
612 IN UINTN BufferSize,
613 IN VOID *Buffer
614 )
615 {
616 SCSI_DISK_DEV *ScsiDiskDevice;
617 EFI_BLOCK_IO_MEDIA *Media;
618 EFI_STATUS Status;
619 UINTN BlockSize;
620 UINTN NumberOfBlocks;
621 BOOLEAN MediaChange;
622 EFI_TPL OldTpl;
623
624 MediaChange = FALSE;
625 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
626 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
627
628 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
629
630 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
631 if (EFI_ERROR (Status)) {
632 Status = EFI_DEVICE_ERROR;
633 goto Done;
634 }
635
636 if (MediaChange) {
637 gBS->ReinstallProtocolInterface (
638 ScsiDiskDevice->Handle,
639 &gEfiBlockIoProtocolGuid,
640 &ScsiDiskDevice->BlkIo,
641 &ScsiDiskDevice->BlkIo
642 );
643 Status = EFI_MEDIA_CHANGED;
644 goto Done;
645 }
646 }
647 //
648 // Get the intrinsic block size
649 //
650 Media = ScsiDiskDevice->BlkIo.Media;
651 BlockSize = Media->BlockSize;
652
653 NumberOfBlocks = BufferSize / BlockSize;
654
655 if (!(Media->MediaPresent)) {
656 Status = EFI_NO_MEDIA;
657 goto Done;
658 }
659
660 if (MediaId != Media->MediaId) {
661 Status = EFI_MEDIA_CHANGED;
662 goto Done;
663 }
664
665 if (BufferSize == 0) {
666 Status = EFI_SUCCESS;
667 goto Done;
668 }
669
670 if (Buffer == NULL) {
671 Status = EFI_INVALID_PARAMETER;
672 goto Done;
673 }
674
675 if (BufferSize % BlockSize != 0) {
676 Status = EFI_BAD_BUFFER_SIZE;
677 goto Done;
678 }
679
680 if (Lba > Media->LastBlock) {
681 Status = EFI_INVALID_PARAMETER;
682 goto Done;
683 }
684
685 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
686 Status = EFI_INVALID_PARAMETER;
687 goto Done;
688 }
689
690 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
691 Status = EFI_INVALID_PARAMETER;
692 goto Done;
693 }
694 //
695 // if all the parameters are valid, then perform read sectors command
696 // to transfer data from device to host.
697 //
698 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
699
700 Done:
701 gBS->RestoreTPL (OldTpl);
702 return Status;
703 }
704
705 /**
706 Flush Block to Disk.
707
708 EFI_SUCCESS is returned directly.
709
710 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
711
712 @retval EFI_SUCCESS All outstanding data was written to the device
713
714 **/
715 EFI_STATUS
716 EFIAPI
717 ScsiDiskFlushBlocks (
718 IN EFI_BLOCK_IO_PROTOCOL *This
719 )
720 {
721 //
722 // return directly
723 //
724 return EFI_SUCCESS;
725 }
726
727
728 /**
729 Detect Device and read out capacity ,if error occurs, parse the sense key.
730
731 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
732 @param MustReadCapacity The flag about reading device capacity
733 @param MediaChange The pointer of flag indicates if media has changed
734
735 @retval EFI_DEVICE_ERROR Indicates that error occurs
736 @retval EFI_SUCCESS Successfully to detect media
737
738 **/
739 EFI_STATUS
740 ScsiDiskDetectMedia (
741 IN SCSI_DISK_DEV *ScsiDiskDevice,
742 IN BOOLEAN MustReadCapacity,
743 OUT BOOLEAN *MediaChange
744 )
745 {
746 EFI_STATUS Status;
747 EFI_SCSI_SENSE_DATA *SenseData;
748 UINTN NumberOfSenseKeys;
749 BOOLEAN NeedRetry;
750 BOOLEAN NeedReadCapacity;
751 UINT8 Retry;
752 UINT8 MaxRetry;
753 EFI_BLOCK_IO_MEDIA OldMedia;
754 UINTN Action;
755 EFI_EVENT TimeoutEvt;
756
757 Status = EFI_SUCCESS;
758 SenseData = NULL;
759 NumberOfSenseKeys = 0;
760 Retry = 0;
761 MaxRetry = 3;
762 Action = ACTION_NO_ACTION;
763 NeedReadCapacity = FALSE;
764 *MediaChange = FALSE;
765 TimeoutEvt = NULL;
766
767 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
768
769 Status = gBS->CreateEvent (
770 EVT_TIMER,
771 TPL_CALLBACK,
772 NULL,
773 NULL,
774 &TimeoutEvt
775 );
776 if (EFI_ERROR (Status)) {
777 return Status;
778 }
779
780 Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));
781 if (EFI_ERROR (Status)) {
782 goto EXIT;
783 }
784
785 //
786 // Sending Test_Unit cmd to poll device status.
787 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
788 // We limit the upper boundary to 120 seconds.
789 //
790 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
791 Status = ScsiDiskTestUnitReady (
792 ScsiDiskDevice,
793 &NeedRetry,
794 &SenseData,
795 &NumberOfSenseKeys
796 );
797 if (!EFI_ERROR (Status)) {
798 Status = DetectMediaParsingSenseKeys (
799 ScsiDiskDevice,
800 SenseData,
801 NumberOfSenseKeys,
802 &Action
803 );
804 if (EFI_ERROR (Status)) {
805 goto EXIT;
806 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
807 continue;
808 } else {
809 break;
810 }
811 } else {
812 Retry++;
813 if (!NeedRetry || (Retry >= MaxRetry)) {
814 goto EXIT;
815 }
816 }
817 }
818
819 if (EFI_ERROR (Status)) {
820 goto EXIT;
821 }
822
823 //
824 // ACTION_NO_ACTION: need not read capacity
825 // other action code: need read capacity
826 //
827 if (Action == ACTION_READ_CAPACITY) {
828 NeedReadCapacity = TRUE;
829 }
830
831 //
832 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
833 // retrieve capacity via Read Capacity command
834 //
835 if (NeedReadCapacity || MustReadCapacity) {
836 //
837 // retrieve media information
838 //
839 for (Retry = 0; Retry < MaxRetry; Retry++) {
840 Status = ScsiDiskReadCapacity (
841 ScsiDiskDevice,
842 &NeedRetry,
843 &SenseData,
844 &NumberOfSenseKeys
845 );
846 if (!EFI_ERROR (Status)) {
847 //
848 // analyze sense key to action
849 //
850 Status = DetectMediaParsingSenseKeys (
851 ScsiDiskDevice,
852 SenseData,
853 NumberOfSenseKeys,
854 &Action
855 );
856 if (EFI_ERROR (Status)) {
857 //
858 // if Status is error, it may indicate crisis error,
859 // so return without retry.
860 //
861 goto EXIT;
862 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
863 Retry = 0;
864 continue;
865 } else {
866 break;
867 }
868 } else {
869 Retry++;
870 if (!NeedRetry || (Retry >= MaxRetry)) {
871 goto EXIT;
872 }
873 }
874 }
875
876 if (EFI_ERROR (Status)) {
877 goto EXIT;
878 }
879 }
880
881 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
882 //
883 // Media change information got from the device
884 //
885 *MediaChange = TRUE;
886 }
887
888 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
889 *MediaChange = TRUE;
890 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
891 }
892
893 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
894 *MediaChange = TRUE;
895 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
896 }
897
898 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
899 *MediaChange = TRUE;
900 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
901 }
902
903 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
904 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
905 //
906 // when change from no media to media present, reset the MediaId to 1.
907 //
908 ScsiDiskDevice->BlkIo.Media->MediaId = 1;
909 } else {
910 //
911 // when no media, reset the MediaId to zero.
912 //
913 ScsiDiskDevice->BlkIo.Media->MediaId = 0;
914 }
915
916 *MediaChange = TRUE;
917 }
918
919 EXIT:
920 if (TimeoutEvt != NULL) {
921 gBS->CloseEvent (TimeoutEvt);
922 }
923 return Status;
924 }
925
926
927 /**
928 Send out Inquiry command to Device.
929
930 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
931 @param NeedRetry Indicates if needs try again when error happens
932
933 @retval EFI_DEVICE_ERROR Indicates that error occurs
934 @retval EFI_SUCCESS Successfully to detect media
935
936 **/
937 EFI_STATUS
938 ScsiDiskInquiryDevice (
939 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
940 OUT BOOLEAN *NeedRetry
941 )
942 {
943 UINT32 InquiryDataLength;
944 UINT8 SenseDataLength;
945 UINT8 HostAdapterStatus;
946 UINT8 TargetStatus;
947 EFI_SCSI_SENSE_DATA *SenseDataArray;
948 UINTN NumberOfSenseKeys;
949 EFI_STATUS Status;
950 UINT8 MaxRetry;
951 UINT8 Index;
952 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
953 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;
954 UINTN PageLength;
955
956 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
957 SenseDataLength = 0;
958
959 Status = ScsiInquiryCommand (
960 ScsiDiskDevice->ScsiIo,
961 SCSI_DISK_TIMEOUT,
962 NULL,
963 &SenseDataLength,
964 &HostAdapterStatus,
965 &TargetStatus,
966 (VOID *) &(ScsiDiskDevice->InquiryData),
967 &InquiryDataLength,
968 FALSE
969 );
970 //
971 // no need to check HostAdapterStatus and TargetStatus
972 //
973 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
974 ParseInquiryData (ScsiDiskDevice);
975
976 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
977 //
978 // Check whether the device supports Block Limits VPD page (0xB0)
979 //
980 SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
981 if (SupportedVpdPages == NULL) {
982 *NeedRetry = FALSE;
983 return EFI_DEVICE_ERROR;
984 }
985 ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
986 InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
987 SenseDataLength = 0;
988 Status = ScsiInquiryCommandEx (
989 ScsiDiskDevice->ScsiIo,
990 SCSI_DISK_TIMEOUT,
991 NULL,
992 &SenseDataLength,
993 &HostAdapterStatus,
994 &TargetStatus,
995 (VOID *) SupportedVpdPages,
996 &InquiryDataLength,
997 TRUE,
998 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
999 );
1000 if (!EFI_ERROR (Status)) {
1001 PageLength = (SupportedVpdPages->PageLength2 << 8)
1002 | SupportedVpdPages->PageLength1;
1003 for (Index = 0; Index < PageLength; Index++) {
1004 if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
1005 break;
1006 }
1007 }
1008
1009 //
1010 // Query the Block Limits VPD page
1011 //
1012 if (Index < PageLength) {
1013 BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1014 if (BlockLimits == NULL) {
1015 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1016 *NeedRetry = FALSE;
1017 return EFI_DEVICE_ERROR;
1018 }
1019 ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1020 InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
1021 SenseDataLength = 0;
1022 Status = ScsiInquiryCommandEx (
1023 ScsiDiskDevice->ScsiIo,
1024 SCSI_DISK_TIMEOUT,
1025 NULL,
1026 &SenseDataLength,
1027 &HostAdapterStatus,
1028 &TargetStatus,
1029 (VOID *) BlockLimits,
1030 &InquiryDataLength,
1031 TRUE,
1032 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1033 );
1034 if (!EFI_ERROR (Status)) {
1035 ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
1036 (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
1037 BlockLimits->OptimalTransferLengthGranularity1;
1038 }
1039
1040 FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1041 }
1042 }
1043
1044 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1045 }
1046 }
1047
1048 if (!EFI_ERROR (Status)) {
1049 return EFI_SUCCESS;
1050
1051 } else if (Status == EFI_NOT_READY) {
1052 *NeedRetry = TRUE;
1053 return EFI_DEVICE_ERROR;
1054
1055 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1056 *NeedRetry = FALSE;
1057 return EFI_DEVICE_ERROR;
1058 }
1059 //
1060 // go ahead to check HostAdapterStatus and TargetStatus
1061 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1062 //
1063
1064 Status = CheckHostAdapterStatus (HostAdapterStatus);
1065 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1066 *NeedRetry = TRUE;
1067 return EFI_DEVICE_ERROR;
1068 } else if (Status == EFI_DEVICE_ERROR) {
1069 //
1070 // reset the scsi channel
1071 //
1072 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1073 *NeedRetry = FALSE;
1074 return EFI_DEVICE_ERROR;
1075 }
1076
1077 Status = CheckTargetStatus (TargetStatus);
1078 if (Status == EFI_NOT_READY) {
1079 //
1080 // reset the scsi device
1081 //
1082 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1083 *NeedRetry = TRUE;
1084 return EFI_DEVICE_ERROR;
1085
1086 } else if (Status == EFI_DEVICE_ERROR) {
1087 *NeedRetry = FALSE;
1088 return EFI_DEVICE_ERROR;
1089 }
1090
1091 //
1092 // if goes here, meant ScsiInquiryCommand() failed.
1093 // if ScsiDiskRequestSenseKeys() succeeds at last,
1094 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1095 //
1096 MaxRetry = 3;
1097 for (Index = 0; Index < MaxRetry; Index++) {
1098 Status = ScsiDiskRequestSenseKeys (
1099 ScsiDiskDevice,
1100 NeedRetry,
1101 &SenseDataArray,
1102 &NumberOfSenseKeys,
1103 TRUE
1104 );
1105 if (!EFI_ERROR (Status)) {
1106 *NeedRetry = TRUE;
1107 return EFI_DEVICE_ERROR;
1108 }
1109
1110 if (!*NeedRetry) {
1111 return EFI_DEVICE_ERROR;
1112 }
1113 }
1114 //
1115 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1116 // set *NeedRetry = FALSE to avoid the outside caller try again.
1117 //
1118 *NeedRetry = FALSE;
1119 return EFI_DEVICE_ERROR;
1120 }
1121
1122 /**
1123 To test device.
1124
1125 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1126 When Test Unit Ready command encounters any error caused by host adapter or
1127 target, return error without retrieving Sense Keys.
1128
1129 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1130 @param NeedRetry The pointer of flag indicates try again
1131 @param SenseDataArray The pointer of an array of sense data
1132 @param NumberOfSenseKeys The pointer of the number of sense data array
1133
1134 @retval EFI_DEVICE_ERROR Indicates that error occurs
1135 @retval EFI_SUCCESS Successfully to test unit
1136
1137 **/
1138 EFI_STATUS
1139 ScsiDiskTestUnitReady (
1140 IN SCSI_DISK_DEV *ScsiDiskDevice,
1141 OUT BOOLEAN *NeedRetry,
1142 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1143 OUT UINTN *NumberOfSenseKeys
1144 )
1145 {
1146 EFI_STATUS Status;
1147 UINT8 SenseDataLength;
1148 UINT8 HostAdapterStatus;
1149 UINT8 TargetStatus;
1150 UINT8 Index;
1151 UINT8 MaxRetry;
1152
1153 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
1154 *NumberOfSenseKeys = 0;
1155
1156 //
1157 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1158 //
1159 Status = ScsiTestUnitReadyCommand (
1160 ScsiDiskDevice->ScsiIo,
1161 SCSI_DISK_TIMEOUT,
1162 ScsiDiskDevice->SenseData,
1163 &SenseDataLength,
1164 &HostAdapterStatus,
1165 &TargetStatus
1166 );
1167 //
1168 // no need to check HostAdapterStatus and TargetStatus
1169 //
1170 if (Status == EFI_NOT_READY) {
1171 *NeedRetry = TRUE;
1172 return EFI_DEVICE_ERROR;
1173
1174 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1175 *NeedRetry = FALSE;
1176 return EFI_DEVICE_ERROR;
1177 }
1178 //
1179 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1180 //
1181
1182 Status = CheckHostAdapterStatus (HostAdapterStatus);
1183 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1184 *NeedRetry = TRUE;
1185 return EFI_DEVICE_ERROR;
1186
1187 } else if (Status == EFI_DEVICE_ERROR) {
1188 //
1189 // reset the scsi channel
1190 //
1191 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1192 *NeedRetry = FALSE;
1193 return EFI_DEVICE_ERROR;
1194 }
1195
1196 Status = CheckTargetStatus (TargetStatus);
1197 if (Status == EFI_NOT_READY) {
1198 //
1199 // reset the scsi device
1200 //
1201 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1202 *NeedRetry = TRUE;
1203 return EFI_DEVICE_ERROR;
1204
1205 } else if (Status == EFI_DEVICE_ERROR) {
1206 *NeedRetry = FALSE;
1207 return EFI_DEVICE_ERROR;
1208 }
1209
1210 if (SenseDataLength != 0) {
1211 *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
1212 *SenseDataArray = ScsiDiskDevice->SenseData;
1213 return EFI_SUCCESS;
1214 }
1215
1216 MaxRetry = 3;
1217 for (Index = 0; Index < MaxRetry; Index++) {
1218 Status = ScsiDiskRequestSenseKeys (
1219 ScsiDiskDevice,
1220 NeedRetry,
1221 SenseDataArray,
1222 NumberOfSenseKeys,
1223 FALSE
1224 );
1225 if (!EFI_ERROR (Status)) {
1226 return EFI_SUCCESS;
1227 }
1228
1229 if (!*NeedRetry) {
1230 return EFI_DEVICE_ERROR;
1231 }
1232 }
1233 //
1234 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1235 // set *NeedRetry = FALSE to avoid the outside caller try again.
1236 //
1237 *NeedRetry = FALSE;
1238 return EFI_DEVICE_ERROR;
1239 }
1240
1241 /**
1242 Parsing Sense Keys which got from request sense command.
1243
1244 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1245 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1246 @param NumberOfSenseKeys The number of sense key
1247 @param Action The pointer of action which indicates what is need to do next
1248
1249 @retval EFI_DEVICE_ERROR Indicates that error occurs
1250 @retval EFI_SUCCESS Successfully to complete the parsing
1251
1252 **/
1253 EFI_STATUS
1254 DetectMediaParsingSenseKeys (
1255 OUT SCSI_DISK_DEV *ScsiDiskDevice,
1256 IN EFI_SCSI_SENSE_DATA *SenseData,
1257 IN UINTN NumberOfSenseKeys,
1258 OUT UINTN *Action
1259 )
1260 {
1261 BOOLEAN RetryLater;
1262
1263 //
1264 // Default is to read capacity, unless..
1265 //
1266 *Action = ACTION_READ_CAPACITY;
1267
1268 if (NumberOfSenseKeys == 0) {
1269 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
1270 *Action = ACTION_NO_ACTION;
1271 }
1272 return EFI_SUCCESS;
1273 }
1274
1275 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
1276 //
1277 // No Sense Key returned from last submitted command
1278 //
1279 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
1280 *Action = ACTION_NO_ACTION;
1281 }
1282 return EFI_SUCCESS;
1283 }
1284
1285 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
1286 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
1287 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
1288 *Action = ACTION_NO_ACTION;
1289 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1290 return EFI_SUCCESS;
1291 }
1292
1293 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
1294 ScsiDiskDevice->BlkIo.Media->MediaId++;
1295 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1296 return EFI_SUCCESS;
1297 }
1298
1299 if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
1300 *Action = ACTION_RETRY_COMMAND_LATER;
1301 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1302 return EFI_SUCCESS;
1303 }
1304
1305 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
1306 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
1307 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1308 return EFI_DEVICE_ERROR;
1309 }
1310
1311 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
1312 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1313 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1314 return EFI_DEVICE_ERROR;
1315 }
1316
1317 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
1318 if (RetryLater) {
1319 *Action = ACTION_RETRY_COMMAND_LATER;
1320 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1321 return EFI_SUCCESS;
1322 }
1323 *Action = ACTION_NO_ACTION;
1324 return EFI_DEVICE_ERROR;
1325 }
1326
1327 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1328 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
1329 return EFI_SUCCESS;
1330 }
1331
1332
1333 /**
1334 Send read capacity command to device and get the device parameter.
1335
1336 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1337 @param NeedRetry The pointer of flag indicates if need a retry
1338 @param SenseDataArray The pointer of an array of sense data
1339 @param NumberOfSenseKeys The number of sense key
1340
1341 @retval EFI_DEVICE_ERROR Indicates that error occurs
1342 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1343
1344 **/
1345 EFI_STATUS
1346 ScsiDiskReadCapacity (
1347 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1348 OUT BOOLEAN *NeedRetry,
1349 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1350 OUT UINTN *NumberOfSenseKeys
1351 )
1352 {
1353 UINT8 HostAdapterStatus;
1354 UINT8 TargetStatus;
1355 EFI_STATUS CommandStatus;
1356 EFI_STATUS Status;
1357 UINT8 Index;
1358 UINT8 MaxRetry;
1359 UINT8 SenseDataLength;
1360 UINT32 DataLength10;
1361 UINT32 DataLength16;
1362 EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
1363 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
1364
1365 CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1366 if (CapacityData10 == NULL) {
1367 *NeedRetry = FALSE;
1368 return EFI_DEVICE_ERROR;
1369 }
1370 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1371 if (CapacityData16 == NULL) {
1372 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1373 *NeedRetry = FALSE;
1374 return EFI_DEVICE_ERROR;
1375 }
1376
1377 SenseDataLength = 0;
1378 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
1379 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
1380 ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1381 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1382
1383 *NumberOfSenseKeys = 0;
1384 *NeedRetry = FALSE;
1385
1386 //
1387 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1388 // 16 byte command should be used to access large hard disk >2TB
1389 //
1390 CommandStatus = ScsiReadCapacityCommand (
1391 ScsiDiskDevice->ScsiIo,
1392 SCSI_DISK_TIMEOUT,
1393 NULL,
1394 &SenseDataLength,
1395 &HostAdapterStatus,
1396 &TargetStatus,
1397 (VOID *) CapacityData10,
1398 &DataLength10,
1399 FALSE
1400 );
1401
1402 ScsiDiskDevice->Cdb16Byte = FALSE;
1403 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
1404 (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
1405 //
1406 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1407 //
1408 ScsiDiskDevice->Cdb16Byte = TRUE;
1409 //
1410 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1411 // and LowestAlignedLba
1412 //
1413 CommandStatus = ScsiReadCapacity16Command (
1414 ScsiDiskDevice->ScsiIo,
1415 SCSI_DISK_TIMEOUT,
1416 NULL,
1417 &SenseDataLength,
1418 &HostAdapterStatus,
1419 &TargetStatus,
1420 (VOID *) CapacityData16,
1421 &DataLength16,
1422 FALSE
1423 );
1424 }
1425
1426 //
1427 // no need to check HostAdapterStatus and TargetStatus
1428 //
1429 if (CommandStatus == EFI_SUCCESS) {
1430 GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
1431 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1432 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1433 return EFI_SUCCESS;
1434 }
1435
1436 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1437 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1438
1439 if (CommandStatus == EFI_NOT_READY) {
1440 *NeedRetry = TRUE;
1441 return EFI_DEVICE_ERROR;
1442 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
1443 *NeedRetry = FALSE;
1444 return EFI_DEVICE_ERROR;
1445 }
1446
1447 //
1448 // go ahead to check HostAdapterStatus and TargetStatus
1449 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1450 //
1451
1452 Status = CheckHostAdapterStatus (HostAdapterStatus);
1453 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1454 *NeedRetry = TRUE;
1455 return EFI_DEVICE_ERROR;
1456
1457 } else if (Status == EFI_DEVICE_ERROR) {
1458 //
1459 // reset the scsi channel
1460 //
1461 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1462 *NeedRetry = FALSE;
1463 return EFI_DEVICE_ERROR;
1464 }
1465
1466 Status = CheckTargetStatus (TargetStatus);
1467 if (Status == EFI_NOT_READY) {
1468 //
1469 // reset the scsi device
1470 //
1471 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1472 *NeedRetry = TRUE;
1473 return EFI_DEVICE_ERROR;
1474
1475 } else if (Status == EFI_DEVICE_ERROR) {
1476 *NeedRetry = FALSE;
1477 return EFI_DEVICE_ERROR;
1478 }
1479
1480 //
1481 // if goes here, meant ScsiReadCapacityCommand() failed.
1482 // if ScsiDiskRequestSenseKeys() succeeds at last,
1483 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1484 //
1485 MaxRetry = 3;
1486 for (Index = 0; Index < MaxRetry; Index++) {
1487
1488 Status = ScsiDiskRequestSenseKeys (
1489 ScsiDiskDevice,
1490 NeedRetry,
1491 SenseDataArray,
1492 NumberOfSenseKeys,
1493 TRUE
1494 );
1495 if (!EFI_ERROR (Status)) {
1496 return EFI_SUCCESS;
1497 }
1498
1499 if (!*NeedRetry) {
1500 return EFI_DEVICE_ERROR;
1501 }
1502 }
1503 //
1504 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1505 // set *NeedRetry = FALSE to avoid the outside caller try again.
1506 //
1507 *NeedRetry = FALSE;
1508 return EFI_DEVICE_ERROR;
1509 }
1510
1511 /**
1512 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1513
1514 @param HostAdapterStatus Host Adapter status
1515
1516 @retval EFI_SUCCESS Host adapter is OK.
1517 @retval EFI_TIMEOUT Timeout.
1518 @retval EFI_NOT_READY Adapter NOT ready.
1519 @retval EFI_DEVICE_ERROR Adapter device error.
1520
1521 **/
1522 EFI_STATUS
1523 CheckHostAdapterStatus (
1524 IN UINT8 HostAdapterStatus
1525 )
1526 {
1527 switch (HostAdapterStatus) {
1528 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
1529 return EFI_SUCCESS;
1530
1531 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
1532 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
1533 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
1534 return EFI_TIMEOUT;
1535
1536 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
1537 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
1538 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
1539 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
1540 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
1541 return EFI_NOT_READY;
1542
1543 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
1544 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
1545 return EFI_DEVICE_ERROR;
1546
1547 default:
1548 return EFI_SUCCESS;
1549 }
1550 }
1551
1552
1553 /**
1554 Check the target status and re-interpret it in EFI_STATUS.
1555
1556 @param TargetStatus Target status
1557
1558 @retval EFI_NOT_READY Device is NOT ready.
1559 @retval EFI_DEVICE_ERROR
1560 @retval EFI_SUCCESS
1561
1562 **/
1563 EFI_STATUS
1564 CheckTargetStatus (
1565 IN UINT8 TargetStatus
1566 )
1567 {
1568 switch (TargetStatus) {
1569 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
1570 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
1571 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
1572 return EFI_SUCCESS;
1573
1574 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
1575 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
1576 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
1577 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
1578 return EFI_NOT_READY;
1579
1580 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
1581 return EFI_DEVICE_ERROR;
1582
1583 default:
1584 return EFI_SUCCESS;
1585 }
1586 }
1587
1588
1589 /**
1590 Retrieve all sense keys from the device.
1591
1592 When encountering error during the process, if retrieve sense keys before
1593 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1594 and NeedRetry set to FALSE; otherwize, return the proper return status.
1595
1596 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1597 @param NeedRetry The pointer of flag indicates if need a retry
1598 @param SenseDataArray The pointer of an array of sense data
1599 @param NumberOfSenseKeys The number of sense key
1600 @param AskResetIfError The flag indicates if need reset when error occurs
1601
1602 @retval EFI_DEVICE_ERROR Indicates that error occurs
1603 @retval EFI_SUCCESS Successfully to request sense key
1604
1605 **/
1606 EFI_STATUS
1607 ScsiDiskRequestSenseKeys (
1608 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1609 OUT BOOLEAN *NeedRetry,
1610 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1611 OUT UINTN *NumberOfSenseKeys,
1612 IN BOOLEAN AskResetIfError
1613 )
1614 {
1615 EFI_SCSI_SENSE_DATA *PtrSenseData;
1616 UINT8 SenseDataLength;
1617 BOOLEAN SenseReq;
1618 EFI_STATUS Status;
1619 EFI_STATUS FallStatus;
1620 UINT8 HostAdapterStatus;
1621 UINT8 TargetStatus;
1622
1623 FallStatus = EFI_SUCCESS;
1624 SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
1625
1626 ZeroMem (
1627 ScsiDiskDevice->SenseData,
1628 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
1629 );
1630
1631 *NumberOfSenseKeys = 0;
1632 *SenseDataArray = ScsiDiskDevice->SenseData;
1633 Status = EFI_SUCCESS;
1634 PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
1635 if (PtrSenseData == NULL) {
1636 return EFI_DEVICE_ERROR;
1637 }
1638
1639 for (SenseReq = TRUE; SenseReq;) {
1640 ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
1641 Status = ScsiRequestSenseCommand (
1642 ScsiDiskDevice->ScsiIo,
1643 SCSI_DISK_TIMEOUT,
1644 PtrSenseData,
1645 &SenseDataLength,
1646 &HostAdapterStatus,
1647 &TargetStatus
1648 );
1649 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
1650 FallStatus = EFI_SUCCESS;
1651
1652 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1653 *NeedRetry = TRUE;
1654 FallStatus = EFI_DEVICE_ERROR;
1655
1656 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1657 *NeedRetry = FALSE;
1658 FallStatus = EFI_DEVICE_ERROR;
1659
1660 } else if (Status == EFI_DEVICE_ERROR) {
1661 if (AskResetIfError) {
1662 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1663 }
1664
1665 FallStatus = EFI_DEVICE_ERROR;
1666 }
1667
1668 if (EFI_ERROR (FallStatus)) {
1669 if (*NumberOfSenseKeys != 0) {
1670 *NeedRetry = FALSE;
1671 Status = EFI_SUCCESS;
1672 goto EXIT;
1673 } else {
1674 Status = EFI_DEVICE_ERROR;
1675 goto EXIT;
1676 }
1677 }
1678
1679 CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
1680 (*NumberOfSenseKeys) += 1;
1681
1682 //
1683 // no more sense key or number of sense keys exceeds predefined,
1684 // skip the loop.
1685 //
1686 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
1687 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
1688 SenseReq = FALSE;
1689 }
1690 }
1691
1692 EXIT:
1693 FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
1694 return Status;
1695 }
1696
1697
1698 /**
1699 Get information from media read capacity command.
1700
1701 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1702 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1703 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1704
1705 **/
1706 VOID
1707 GetMediaInfo (
1708 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1709 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
1710 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
1711 )
1712 {
1713 UINT8 *Ptr;
1714
1715 if (!ScsiDiskDevice->Cdb16Byte) {
1716 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |
1717 (Capacity10->LastLba2 << 16) |
1718 (Capacity10->LastLba1 << 8) |
1719 Capacity10->LastLba0;
1720
1721 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
1722 (Capacity10->BlockSize2 << 16) |
1723 (Capacity10->BlockSize1 << 8) |
1724 Capacity10->BlockSize0;
1725 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
1726 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;
1727 } else {
1728 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
1729 *Ptr++ = Capacity16->LastLba0;
1730 *Ptr++ = Capacity16->LastLba1;
1731 *Ptr++ = Capacity16->LastLba2;
1732 *Ptr++ = Capacity16->LastLba3;
1733 *Ptr++ = Capacity16->LastLba4;
1734 *Ptr++ = Capacity16->LastLba5;
1735 *Ptr++ = Capacity16->LastLba6;
1736 *Ptr = Capacity16->LastLba7;
1737
1738 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
1739 (Capacity16->BlockSize2 << 16) |
1740 (Capacity16->BlockSize1 << 8) |
1741 Capacity16->BlockSize0;
1742
1743 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
1744 Capacity16->LowestAlignLogic1;
1745 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);
1746 }
1747
1748 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
1749 }
1750
1751 /**
1752 Parse Inquiry data.
1753
1754 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1755
1756 **/
1757 VOID
1758 ParseInquiryData (
1759 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
1760 )
1761 {
1762 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
1763 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
1764 }
1765
1766 /**
1767 Read sector from SCSI Disk.
1768
1769 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1770 @param Buffer The buffer to fill in the read out data
1771 @param Lba Logic block address
1772 @param NumberOfBlocks The number of blocks to read
1773
1774 @retval EFI_DEVICE_ERROR Indicates a device error.
1775 @retval EFI_SUCCESS Operation is successful.
1776
1777 **/
1778 EFI_STATUS
1779 ScsiDiskReadSectors (
1780 IN SCSI_DISK_DEV *ScsiDiskDevice,
1781 OUT VOID *Buffer,
1782 IN EFI_LBA Lba,
1783 IN UINTN NumberOfBlocks
1784 )
1785 {
1786 UINTN BlocksRemaining;
1787 UINT8 *PtrBuffer;
1788 UINT32 BlockSize;
1789 UINT32 ByteCount;
1790 UINT32 MaxBlock;
1791 UINT32 SectorCount;
1792 UINT32 NextSectorCount;
1793 UINT64 Timeout;
1794 EFI_STATUS Status;
1795 UINT8 Index;
1796 UINT8 MaxRetry;
1797 BOOLEAN NeedRetry;
1798
1799 Status = EFI_SUCCESS;
1800
1801 BlocksRemaining = NumberOfBlocks;
1802 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1803
1804 //
1805 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1806 //
1807 if (!ScsiDiskDevice->Cdb16Byte) {
1808 MaxBlock = 0xFFFF;
1809 } else {
1810 MaxBlock = 0xFFFFFFFF;
1811 }
1812
1813 PtrBuffer = Buffer;
1814
1815 while (BlocksRemaining > 0) {
1816
1817 if (BlocksRemaining <= MaxBlock) {
1818 if (!ScsiDiskDevice->Cdb16Byte) {
1819 SectorCount = (UINT16) BlocksRemaining;
1820 } else {
1821 SectorCount = (UINT32) BlocksRemaining;
1822 }
1823 } else {
1824 SectorCount = MaxBlock;
1825 }
1826
1827 ByteCount = SectorCount * BlockSize;
1828 //
1829 // |------------------------|-----------------|------------------|-----------------|
1830 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
1831 // |------------------------|-----------------|------------------|-----------------|
1832 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
1833 // |------------------------|-----------------|------------------|-----------------|
1834 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
1835 // |------------------------|-----------------|------------------|-----------------|
1836 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
1837 // |------------------------|-----------------|------------------|-----------------|
1838 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
1839 // |------------------------|-----------------|------------------|-----------------|
1840 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
1841 // |------------------------|-----------------|------------------|-----------------|
1842 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
1843 // |------------------------|-----------------|------------------|-----------------|
1844 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
1845 // |------------------------|-----------------|------------------|-----------------|
1846 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
1847 // |------------------------|-----------------|------------------|-----------------|
1848 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
1849 // |------------------------|-----------------|------------------|-----------------|
1850 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
1851 // |------------------------|-----------------|------------------|-----------------|
1852 //
1853 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
1854 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
1855 // From the above table, we could know 2.1Mbytes per second is lowest one.
1856 // The timout value is rounded up to nearest integar and here an additional 30s is added
1857 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
1858 // commands in the Standby/Idle mode.
1859 //
1860 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
1861
1862 MaxRetry = 2;
1863 for (Index = 0; Index < MaxRetry; Index++) {
1864 if (!ScsiDiskDevice->Cdb16Byte) {
1865 Status = ScsiDiskRead10 (
1866 ScsiDiskDevice,
1867 &NeedRetry,
1868 Timeout,
1869 PtrBuffer,
1870 &ByteCount,
1871 (UINT32) Lba,
1872 SectorCount
1873 );
1874 } else {
1875 Status = ScsiDiskRead16 (
1876 ScsiDiskDevice,
1877 &NeedRetry,
1878 Timeout,
1879 PtrBuffer,
1880 &ByteCount,
1881 Lba,
1882 SectorCount
1883 );
1884 }
1885 if (!EFI_ERROR (Status)) {
1886 break;
1887 }
1888
1889 if (!NeedRetry) {
1890 return EFI_DEVICE_ERROR;
1891 }
1892
1893 //
1894 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
1895 // lowered ByteCount on output, we must make sure that we lower
1896 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
1897 // it is invalid to request more sectors in the CDB than the entire
1898 // transfer (ie. ByteCount) can carry.
1899 //
1900 // In addition, ByteCount is only expected to go down, or stay unchaged.
1901 // Therefore we don't need to update Timeout: the original timeout should
1902 // accommodate shorter transfers too.
1903 //
1904 NextSectorCount = ByteCount / BlockSize;
1905 if (NextSectorCount < SectorCount) {
1906 SectorCount = NextSectorCount;
1907 //
1908 // Account for any rounding down.
1909 //
1910 ByteCount = SectorCount * BlockSize;
1911 }
1912 }
1913
1914 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
1915 return EFI_DEVICE_ERROR;
1916 }
1917
1918 //
1919 // actual transferred sectors
1920 //
1921 SectorCount = ByteCount / BlockSize;
1922
1923 Lba += SectorCount;
1924 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
1925 BlocksRemaining -= SectorCount;
1926 }
1927
1928 return EFI_SUCCESS;
1929 }
1930
1931 /**
1932 Write sector to SCSI Disk.
1933
1934 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1935 @param Buffer The buffer of data to be written into SCSI Disk
1936 @param Lba Logic block address
1937 @param NumberOfBlocks The number of blocks to read
1938
1939 @retval EFI_DEVICE_ERROR Indicates a device error.
1940 @retval EFI_SUCCESS Operation is successful.
1941
1942 **/
1943 EFI_STATUS
1944 ScsiDiskWriteSectors (
1945 IN SCSI_DISK_DEV *ScsiDiskDevice,
1946 IN VOID *Buffer,
1947 IN EFI_LBA Lba,
1948 IN UINTN NumberOfBlocks
1949 )
1950 {
1951 UINTN BlocksRemaining;
1952 UINT8 *PtrBuffer;
1953 UINT32 BlockSize;
1954 UINT32 ByteCount;
1955 UINT32 MaxBlock;
1956 UINT32 SectorCount;
1957 UINT32 NextSectorCount;
1958 UINT64 Timeout;
1959 EFI_STATUS Status;
1960 UINT8 Index;
1961 UINT8 MaxRetry;
1962 BOOLEAN NeedRetry;
1963
1964 Status = EFI_SUCCESS;
1965
1966 BlocksRemaining = NumberOfBlocks;
1967 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1968
1969 //
1970 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1971 //
1972 if (!ScsiDiskDevice->Cdb16Byte) {
1973 MaxBlock = 0xFFFF;
1974 } else {
1975 MaxBlock = 0xFFFFFFFF;
1976 }
1977
1978 PtrBuffer = Buffer;
1979
1980 while (BlocksRemaining > 0) {
1981
1982 if (BlocksRemaining <= MaxBlock) {
1983 if (!ScsiDiskDevice->Cdb16Byte) {
1984 SectorCount = (UINT16) BlocksRemaining;
1985 } else {
1986 SectorCount = (UINT32) BlocksRemaining;
1987 }
1988 } else {
1989 SectorCount = MaxBlock;
1990 }
1991
1992 ByteCount = SectorCount * BlockSize;
1993 //
1994 // |------------------------|-----------------|------------------|-----------------|
1995 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
1996 // |------------------------|-----------------|------------------|-----------------|
1997 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
1998 // |------------------------|-----------------|------------------|-----------------|
1999 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2000 // |------------------------|-----------------|------------------|-----------------|
2001 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2002 // |------------------------|-----------------|------------------|-----------------|
2003 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2004 // |------------------------|-----------------|------------------|-----------------|
2005 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2006 // |------------------------|-----------------|------------------|-----------------|
2007 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2008 // |------------------------|-----------------|------------------|-----------------|
2009 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2010 // |------------------------|-----------------|------------------|-----------------|
2011 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2012 // |------------------------|-----------------|------------------|-----------------|
2013 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2014 // |------------------------|-----------------|------------------|-----------------|
2015 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2016 // |------------------------|-----------------|------------------|-----------------|
2017 //
2018 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2019 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2020 // From the above table, we could know 2.1Mbytes per second is lowest one.
2021 // The timout value is rounded up to nearest integar and here an additional 30s is added
2022 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2023 // commands in the Standby/Idle mode.
2024 //
2025 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2026 MaxRetry = 2;
2027 for (Index = 0; Index < MaxRetry; Index++) {
2028 if (!ScsiDiskDevice->Cdb16Byte) {
2029 Status = ScsiDiskWrite10 (
2030 ScsiDiskDevice,
2031 &NeedRetry,
2032 Timeout,
2033 PtrBuffer,
2034 &ByteCount,
2035 (UINT32) Lba,
2036 SectorCount
2037 );
2038 } else {
2039 Status = ScsiDiskWrite16 (
2040 ScsiDiskDevice,
2041 &NeedRetry,
2042 Timeout,
2043 PtrBuffer,
2044 &ByteCount,
2045 Lba,
2046 SectorCount
2047 );
2048 }
2049 if (!EFI_ERROR (Status)) {
2050 break;
2051 }
2052
2053 if (!NeedRetry) {
2054 return EFI_DEVICE_ERROR;
2055 }
2056
2057 //
2058 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2059 // has lowered ByteCount on output, we must make sure that we lower
2060 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2061 // it is invalid to request more sectors in the CDB than the entire
2062 // transfer (ie. ByteCount) can carry.
2063 //
2064 // In addition, ByteCount is only expected to go down, or stay unchaged.
2065 // Therefore we don't need to update Timeout: the original timeout should
2066 // accommodate shorter transfers too.
2067 //
2068 NextSectorCount = ByteCount / BlockSize;
2069 if (NextSectorCount < SectorCount) {
2070 SectorCount = NextSectorCount;
2071 //
2072 // Account for any rounding down.
2073 //
2074 ByteCount = SectorCount * BlockSize;
2075 }
2076 }
2077
2078 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
2079 return EFI_DEVICE_ERROR;
2080 }
2081 //
2082 // actual transferred sectors
2083 //
2084 SectorCount = ByteCount / BlockSize;
2085
2086 Lba += SectorCount;
2087 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2088 BlocksRemaining -= SectorCount;
2089 }
2090
2091 return EFI_SUCCESS;
2092 }
2093
2094
2095 /**
2096 Submit Read(10) command.
2097
2098 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2099 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2100 @param Timeout The time to complete the command
2101 @param DataBuffer The buffer to fill with the read out data
2102 @param DataLength The length of buffer
2103 @param StartLba The start logic block address
2104 @param SectorCount The number of blocks to read
2105
2106 @return EFI_STATUS is returned by calling ScsiRead10Command().
2107 **/
2108 EFI_STATUS
2109 ScsiDiskRead10 (
2110 IN SCSI_DISK_DEV *ScsiDiskDevice,
2111 OUT BOOLEAN *NeedRetry,
2112 IN UINT64 Timeout,
2113 OUT UINT8 *DataBuffer,
2114 IN OUT UINT32 *DataLength,
2115 IN UINT32 StartLba,
2116 IN UINT32 SectorCount
2117 )
2118 {
2119 UINT8 SenseDataLength;
2120 EFI_STATUS Status;
2121 EFI_STATUS ReturnStatus;
2122 UINT8 HostAdapterStatus;
2123 UINT8 TargetStatus;
2124 UINTN Action;
2125
2126 //
2127 // Implement a backoff algorithem to resolve some compatibility issues that
2128 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2129 // big data in a single operation.
2130 // This algorithem will at first try to execute original request. If the request fails
2131 // with media error sense data or else, it will reduce the transfer length to half and
2132 // try again till the operation succeeds or fails with one sector transfer length.
2133 //
2134 BackOff:
2135 *NeedRetry = FALSE;
2136 Action = ACTION_NO_ACTION;
2137 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2138 ReturnStatus = ScsiRead10Command (
2139 ScsiDiskDevice->ScsiIo,
2140 Timeout,
2141 ScsiDiskDevice->SenseData,
2142 &SenseDataLength,
2143 &HostAdapterStatus,
2144 &TargetStatus,
2145 DataBuffer,
2146 DataLength,
2147 StartLba,
2148 SectorCount
2149 );
2150
2151 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
2152 *NeedRetry = TRUE;
2153 return EFI_DEVICE_ERROR;
2154 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
2155 *NeedRetry = FALSE;
2156 return ReturnStatus;
2157 }
2158
2159 //
2160 // go ahead to check HostAdapterStatus and TargetStatus
2161 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2162 //
2163 Status = CheckHostAdapterStatus (HostAdapterStatus);
2164 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2165 *NeedRetry = TRUE;
2166 return EFI_DEVICE_ERROR;
2167 } else if (Status == EFI_DEVICE_ERROR) {
2168 //
2169 // reset the scsi channel
2170 //
2171 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2172 *NeedRetry = FALSE;
2173 return EFI_DEVICE_ERROR;
2174 }
2175
2176 Status = CheckTargetStatus (TargetStatus);
2177 if (Status == EFI_NOT_READY) {
2178 //
2179 // reset the scsi device
2180 //
2181 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2182 *NeedRetry = TRUE;
2183 return EFI_DEVICE_ERROR;
2184 } else if (Status == EFI_DEVICE_ERROR) {
2185 *NeedRetry = FALSE;
2186 return EFI_DEVICE_ERROR;
2187 }
2188
2189 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
2190 DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
2191 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
2192 if (Action == ACTION_RETRY_COMMAND_LATER) {
2193 *NeedRetry = TRUE;
2194 return EFI_DEVICE_ERROR;
2195 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
2196 if (SectorCount <= 1) {
2197 //
2198 // Jump out if the operation still fails with one sector transfer length.
2199 //
2200 *NeedRetry = FALSE;
2201 return EFI_DEVICE_ERROR;
2202 }
2203 //
2204 // Try again with half length if the sense data shows we need to retry.
2205 //
2206 SectorCount >>= 1;
2207 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
2208 goto BackOff;
2209 } else {
2210 *NeedRetry = FALSE;
2211 return EFI_DEVICE_ERROR;
2212 }
2213 }
2214
2215 return ReturnStatus;
2216 }
2217
2218
2219 /**
2220 Submit Write(10) Command.
2221
2222 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2223 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2224 @param Timeout The time to complete the command
2225 @param DataBuffer The buffer to fill with the read out data
2226 @param DataLength The length of buffer
2227 @param StartLba The start logic block address
2228 @param SectorCount The number of blocks to write
2229
2230 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2231
2232 **/
2233 EFI_STATUS
2234 ScsiDiskWrite10 (
2235 IN SCSI_DISK_DEV *ScsiDiskDevice,
2236 OUT BOOLEAN *NeedRetry,
2237 IN UINT64 Timeout,
2238 IN UINT8 *DataBuffer,
2239 IN OUT UINT32 *DataLength,
2240 IN UINT32 StartLba,
2241 IN UINT32 SectorCount
2242 )
2243 {
2244 EFI_STATUS Status;
2245 EFI_STATUS ReturnStatus;
2246 UINT8 SenseDataLength;
2247 UINT8 HostAdapterStatus;
2248 UINT8 TargetStatus;
2249 UINTN Action;
2250
2251 //
2252 // Implement a backoff algorithem to resolve some compatibility issues that
2253 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2254 // big data in a single operation.
2255 // This algorithem will at first try to execute original request. If the request fails
2256 // with media error sense data or else, it will reduce the transfer length to half and
2257 // try again till the operation succeeds or fails with one sector transfer length.
2258 //
2259 BackOff:
2260 *NeedRetry = FALSE;
2261 Action = ACTION_NO_ACTION;
2262 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2263 ReturnStatus = ScsiWrite10Command (
2264 ScsiDiskDevice->ScsiIo,
2265 Timeout,
2266 ScsiDiskDevice->SenseData,
2267 &SenseDataLength,
2268 &HostAdapterStatus,
2269 &TargetStatus,
2270 DataBuffer,
2271 DataLength,
2272 StartLba,
2273 SectorCount
2274 );
2275 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
2276 *NeedRetry = TRUE;
2277 return EFI_DEVICE_ERROR;
2278 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
2279 *NeedRetry = FALSE;
2280 return ReturnStatus;
2281 }
2282
2283 //
2284 // go ahead to check HostAdapterStatus and TargetStatus
2285 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2286 //
2287 Status = CheckHostAdapterStatus (HostAdapterStatus);
2288 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2289 *NeedRetry = TRUE;
2290 return EFI_DEVICE_ERROR;
2291 } else if (Status == EFI_DEVICE_ERROR) {
2292 //
2293 // reset the scsi channel
2294 //
2295 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2296 *NeedRetry = FALSE;
2297 return EFI_DEVICE_ERROR;
2298 }
2299
2300 Status = CheckTargetStatus (TargetStatus);
2301 if (Status == EFI_NOT_READY) {
2302 //
2303 // reset the scsi device
2304 //
2305 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2306 *NeedRetry = TRUE;
2307 return EFI_DEVICE_ERROR;
2308 } else if (Status == EFI_DEVICE_ERROR) {
2309 *NeedRetry = FALSE;
2310 return EFI_DEVICE_ERROR;
2311 }
2312
2313 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
2314 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
2315 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
2316 if (Action == ACTION_RETRY_COMMAND_LATER) {
2317 *NeedRetry = TRUE;
2318 return EFI_DEVICE_ERROR;
2319 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
2320 if (SectorCount <= 1) {
2321 //
2322 // Jump out if the operation still fails with one sector transfer length.
2323 //
2324 *NeedRetry = FALSE;
2325 return EFI_DEVICE_ERROR;
2326 }
2327 //
2328 // Try again with half length if the sense data shows we need to retry.
2329 //
2330 SectorCount >>= 1;
2331 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
2332 goto BackOff;
2333 } else {
2334 *NeedRetry = FALSE;
2335 return EFI_DEVICE_ERROR;
2336 }
2337 }
2338
2339 return ReturnStatus;
2340 }
2341
2342
2343 /**
2344 Submit Read(16) command.
2345
2346 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2347 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2348 @param Timeout The time to complete the command
2349 @param DataBuffer The buffer to fill with the read out data
2350 @param DataLength The length of buffer
2351 @param StartLba The start logic block address
2352 @param SectorCount The number of blocks to read
2353
2354 @return EFI_STATUS is returned by calling ScsiRead16Command().
2355 **/
2356 EFI_STATUS
2357 ScsiDiskRead16 (
2358 IN SCSI_DISK_DEV *ScsiDiskDevice,
2359 OUT BOOLEAN *NeedRetry,
2360 IN UINT64 Timeout,
2361 OUT UINT8 *DataBuffer,
2362 IN OUT UINT32 *DataLength,
2363 IN UINT64 StartLba,
2364 IN UINT32 SectorCount
2365 )
2366 {
2367 UINT8 SenseDataLength;
2368 EFI_STATUS Status;
2369 EFI_STATUS ReturnStatus;
2370 UINT8 HostAdapterStatus;
2371 UINT8 TargetStatus;
2372 UINTN Action;
2373
2374 //
2375 // Implement a backoff algorithem to resolve some compatibility issues that
2376 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2377 // big data in a single operation.
2378 // This algorithem will at first try to execute original request. If the request fails
2379 // with media error sense data or else, it will reduce the transfer length to half and
2380 // try again till the operation succeeds or fails with one sector transfer length.
2381 //
2382 BackOff:
2383 *NeedRetry = FALSE;
2384 Action = ACTION_NO_ACTION;
2385 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2386 ReturnStatus = ScsiRead16Command (
2387 ScsiDiskDevice->ScsiIo,
2388 Timeout,
2389 ScsiDiskDevice->SenseData,
2390 &SenseDataLength,
2391 &HostAdapterStatus,
2392 &TargetStatus,
2393 DataBuffer,
2394 DataLength,
2395 StartLba,
2396 SectorCount
2397 );
2398 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
2399 *NeedRetry = TRUE;
2400 return EFI_DEVICE_ERROR;
2401 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
2402 *NeedRetry = FALSE;
2403 return ReturnStatus;
2404 }
2405
2406 //
2407 // go ahead to check HostAdapterStatus and TargetStatus
2408 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2409 //
2410 Status = CheckHostAdapterStatus (HostAdapterStatus);
2411 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2412 *NeedRetry = TRUE;
2413 return EFI_DEVICE_ERROR;
2414 } else if (Status == EFI_DEVICE_ERROR) {
2415 //
2416 // reset the scsi channel
2417 //
2418 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2419 *NeedRetry = FALSE;
2420 return EFI_DEVICE_ERROR;
2421 }
2422
2423 Status = CheckTargetStatus (TargetStatus);
2424 if (Status == EFI_NOT_READY) {
2425 //
2426 // reset the scsi device
2427 //
2428 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2429 *NeedRetry = TRUE;
2430 return EFI_DEVICE_ERROR;
2431 } else if (Status == EFI_DEVICE_ERROR) {
2432 *NeedRetry = FALSE;
2433 return EFI_DEVICE_ERROR;
2434 }
2435
2436 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
2437 DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
2438 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
2439 if (Action == ACTION_RETRY_COMMAND_LATER) {
2440 *NeedRetry = TRUE;
2441 return EFI_DEVICE_ERROR;
2442 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
2443 if (SectorCount <= 1) {
2444 //
2445 // Jump out if the operation still fails with one sector transfer length.
2446 //
2447 *NeedRetry = FALSE;
2448 return EFI_DEVICE_ERROR;
2449 }
2450 //
2451 // Try again with half length if the sense data shows we need to retry.
2452 //
2453 SectorCount >>= 1;
2454 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
2455 goto BackOff;
2456 } else {
2457 *NeedRetry = FALSE;
2458 return EFI_DEVICE_ERROR;
2459 }
2460 }
2461
2462 return ReturnStatus;
2463 }
2464
2465
2466 /**
2467 Submit Write(16) Command.
2468
2469 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2470 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2471 @param Timeout The time to complete the command
2472 @param DataBuffer The buffer to fill with the read out data
2473 @param DataLength The length of buffer
2474 @param StartLba The start logic block address
2475 @param SectorCount The number of blocks to write
2476
2477 @return EFI_STATUS is returned by calling ScsiWrite16Command().
2478
2479 **/
2480 EFI_STATUS
2481 ScsiDiskWrite16 (
2482 IN SCSI_DISK_DEV *ScsiDiskDevice,
2483 OUT BOOLEAN *NeedRetry,
2484 IN UINT64 Timeout,
2485 IN UINT8 *DataBuffer,
2486 IN OUT UINT32 *DataLength,
2487 IN UINT64 StartLba,
2488 IN UINT32 SectorCount
2489 )
2490 {
2491 EFI_STATUS Status;
2492 EFI_STATUS ReturnStatus;
2493 UINT8 SenseDataLength;
2494 UINT8 HostAdapterStatus;
2495 UINT8 TargetStatus;
2496 UINTN Action;
2497
2498 //
2499 // Implement a backoff algorithem to resolve some compatibility issues that
2500 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2501 // big data in a single operation.
2502 // This algorithem will at first try to execute original request. If the request fails
2503 // with media error sense data or else, it will reduce the transfer length to half and
2504 // try again till the operation succeeds or fails with one sector transfer length.
2505 //
2506 BackOff:
2507 *NeedRetry = FALSE;
2508 Action = ACTION_NO_ACTION;
2509 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2510 ReturnStatus = ScsiWrite16Command (
2511 ScsiDiskDevice->ScsiIo,
2512 Timeout,
2513 ScsiDiskDevice->SenseData,
2514 &SenseDataLength,
2515 &HostAdapterStatus,
2516 &TargetStatus,
2517 DataBuffer,
2518 DataLength,
2519 StartLba,
2520 SectorCount
2521 );
2522 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
2523 *NeedRetry = TRUE;
2524 return EFI_DEVICE_ERROR;
2525 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
2526 *NeedRetry = FALSE;
2527 return ReturnStatus;
2528 }
2529
2530 //
2531 // go ahead to check HostAdapterStatus and TargetStatus
2532 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2533 //
2534 Status = CheckHostAdapterStatus (HostAdapterStatus);
2535 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2536 *NeedRetry = TRUE;
2537 return EFI_DEVICE_ERROR;
2538 } else if (Status == EFI_DEVICE_ERROR) {
2539 //
2540 // reset the scsi channel
2541 //
2542 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2543 *NeedRetry = FALSE;
2544 return EFI_DEVICE_ERROR;
2545 }
2546
2547 Status = CheckTargetStatus (TargetStatus);
2548 if (Status == EFI_NOT_READY) {
2549 //
2550 // reset the scsi device
2551 //
2552 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2553 *NeedRetry = TRUE;
2554 return EFI_DEVICE_ERROR;
2555 } else if (Status == EFI_DEVICE_ERROR) {
2556 *NeedRetry = FALSE;
2557 return EFI_DEVICE_ERROR;
2558 }
2559
2560 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
2561 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
2562 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
2563 if (Action == ACTION_RETRY_COMMAND_LATER) {
2564 *NeedRetry = TRUE;
2565 return EFI_DEVICE_ERROR;
2566 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
2567 if (SectorCount <= 1) {
2568 //
2569 // Jump out if the operation still fails with one sector transfer length.
2570 //
2571 *NeedRetry = FALSE;
2572 return EFI_DEVICE_ERROR;
2573 }
2574 //
2575 // Try again with half length if the sense data shows we need to retry.
2576 //
2577 SectorCount >>= 1;
2578 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
2579 goto BackOff;
2580 } else {
2581 *NeedRetry = FALSE;
2582 return EFI_DEVICE_ERROR;
2583 }
2584 }
2585
2586 return ReturnStatus;
2587 }
2588
2589
2590 /**
2591 Check sense key to find if media presents.
2592
2593 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2594 @param SenseCounts The number of sense key
2595
2596 @retval TRUE NOT any media
2597 @retval FALSE Media presents
2598 **/
2599 BOOLEAN
2600 ScsiDiskIsNoMedia (
2601 IN EFI_SCSI_SENSE_DATA *SenseData,
2602 IN UINTN SenseCounts
2603 )
2604 {
2605 EFI_SCSI_SENSE_DATA *SensePtr;
2606 UINTN Index;
2607 BOOLEAN IsNoMedia;
2608
2609 IsNoMedia = FALSE;
2610 SensePtr = SenseData;
2611
2612 for (Index = 0; Index < SenseCounts; Index++) {
2613 //
2614 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2615 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2616 //
2617 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
2618 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
2619 IsNoMedia = TRUE;
2620 }
2621 SensePtr++;
2622 }
2623
2624 return IsNoMedia;
2625 }
2626
2627
2628 /**
2629 Parse sense key.
2630
2631 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2632 @param SenseCounts The number of sense key
2633
2634 @retval TRUE Error
2635 @retval FALSE NOT error
2636
2637 **/
2638 BOOLEAN
2639 ScsiDiskIsMediaError (
2640 IN EFI_SCSI_SENSE_DATA *SenseData,
2641 IN UINTN SenseCounts
2642 )
2643 {
2644 EFI_SCSI_SENSE_DATA *SensePtr;
2645 UINTN Index;
2646 BOOLEAN IsError;
2647
2648 IsError = FALSE;
2649 SensePtr = SenseData;
2650
2651 for (Index = 0; Index < SenseCounts; Index++) {
2652
2653 switch (SensePtr->Sense_Key) {
2654
2655 case EFI_SCSI_SK_MEDIUM_ERROR:
2656 //
2657 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2658 //
2659 switch (SensePtr->Addnl_Sense_Code) {
2660
2661 //
2662 // fall through
2663 //
2664 case EFI_SCSI_ASC_MEDIA_ERR1:
2665
2666 //
2667 // fall through
2668 //
2669 case EFI_SCSI_ASC_MEDIA_ERR2:
2670
2671 //
2672 // fall through
2673 //
2674 case EFI_SCSI_ASC_MEDIA_ERR3:
2675 case EFI_SCSI_ASC_MEDIA_ERR4:
2676 IsError = TRUE;
2677 break;
2678
2679 default:
2680 break;
2681 }
2682
2683 break;
2684
2685 case EFI_SCSI_SK_NOT_READY:
2686 //
2687 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2688 //
2689 switch (SensePtr->Addnl_Sense_Code) {
2690 //
2691 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2692 //
2693 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
2694 IsError = TRUE;
2695 break;
2696
2697 default:
2698 break;
2699 }
2700 break;
2701
2702 default:
2703 break;
2704 }
2705
2706 SensePtr++;
2707 }
2708
2709 return IsError;
2710 }
2711
2712
2713 /**
2714 Check sense key to find if hardware error happens.
2715
2716 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2717 @param SenseCounts The number of sense key
2718
2719 @retval TRUE Hardware error exits.
2720 @retval FALSE NO error.
2721
2722 **/
2723 BOOLEAN
2724 ScsiDiskIsHardwareError (
2725 IN EFI_SCSI_SENSE_DATA *SenseData,
2726 IN UINTN SenseCounts
2727 )
2728 {
2729 EFI_SCSI_SENSE_DATA *SensePtr;
2730 UINTN Index;
2731 BOOLEAN IsError;
2732
2733 IsError = FALSE;
2734 SensePtr = SenseData;
2735
2736 for (Index = 0; Index < SenseCounts; Index++) {
2737
2738 //
2739 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2740 //
2741 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
2742 IsError = TRUE;
2743 }
2744
2745 SensePtr++;
2746 }
2747
2748 return IsError;
2749 }
2750
2751
2752 /**
2753 Check sense key to find if media has changed.
2754
2755 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2756 @param SenseCounts The number of sense key
2757
2758 @retval TRUE Media is changed.
2759 @retval FALSE Media is NOT changed.
2760 **/
2761 BOOLEAN
2762 ScsiDiskIsMediaChange (
2763 IN EFI_SCSI_SENSE_DATA *SenseData,
2764 IN UINTN SenseCounts
2765 )
2766 {
2767 EFI_SCSI_SENSE_DATA *SensePtr;
2768 UINTN Index;
2769 BOOLEAN IsMediaChanged;
2770
2771 IsMediaChanged = FALSE;
2772 SensePtr = SenseData;
2773
2774 for (Index = 0; Index < SenseCounts; Index++) {
2775 //
2776 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2777 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2778 //
2779 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2780 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
2781 IsMediaChanged = TRUE;
2782 }
2783
2784 SensePtr++;
2785 }
2786
2787 return IsMediaChanged;
2788 }
2789
2790 /**
2791 Check sense key to find if reset happens.
2792
2793 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2794 @param SenseCounts The number of sense key
2795
2796 @retval TRUE It is reset before.
2797 @retval FALSE It is NOT reset before.
2798
2799 **/
2800 BOOLEAN
2801 ScsiDiskIsResetBefore (
2802 IN EFI_SCSI_SENSE_DATA *SenseData,
2803 IN UINTN SenseCounts
2804 )
2805 {
2806 EFI_SCSI_SENSE_DATA *SensePtr;
2807 UINTN Index;
2808 BOOLEAN IsResetBefore;
2809
2810 IsResetBefore = FALSE;
2811 SensePtr = SenseData;
2812
2813 for (Index = 0; Index < SenseCounts; Index++) {
2814
2815 //
2816 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2817 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2818 //
2819 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2820 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
2821 IsResetBefore = TRUE;
2822 }
2823
2824 SensePtr++;
2825 }
2826
2827 return IsResetBefore;
2828 }
2829
2830 /**
2831 Check sense key to find if the drive is ready.
2832
2833 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2834 @param SenseCounts The number of sense key
2835 @param RetryLater The flag means if need a retry
2836
2837 @retval TRUE Drive is ready.
2838 @retval FALSE Drive is NOT ready.
2839
2840 **/
2841 BOOLEAN
2842 ScsiDiskIsDriveReady (
2843 IN EFI_SCSI_SENSE_DATA *SenseData,
2844 IN UINTN SenseCounts,
2845 OUT BOOLEAN *RetryLater
2846 )
2847 {
2848 EFI_SCSI_SENSE_DATA *SensePtr;
2849 UINTN Index;
2850 BOOLEAN IsReady;
2851
2852 IsReady = TRUE;
2853 *RetryLater = FALSE;
2854 SensePtr = SenseData;
2855
2856 for (Index = 0; Index < SenseCounts; Index++) {
2857
2858 switch (SensePtr->Sense_Key) {
2859
2860 case EFI_SCSI_SK_NOT_READY:
2861 //
2862 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2863 //
2864 switch (SensePtr->Addnl_Sense_Code) {
2865 case EFI_SCSI_ASC_NOT_READY:
2866 //
2867 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2868 //
2869 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
2870 case EFI_SCSI_ASCQ_IN_PROGRESS:
2871 //
2872 // Additional Sense Code Qualifier is
2873 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2874 //
2875 IsReady = FALSE;
2876 *RetryLater = TRUE;
2877 break;
2878
2879 default:
2880 IsReady = FALSE;
2881 *RetryLater = FALSE;
2882 break;
2883 }
2884 break;
2885
2886 default:
2887 break;
2888 }
2889 break;
2890
2891 default:
2892 break;
2893 }
2894
2895 SensePtr++;
2896 }
2897
2898 return IsReady;
2899 }
2900
2901 /**
2902 Check sense key to find if it has sense key.
2903
2904 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2905 @param SenseCounts - The number of sense key
2906
2907 @retval TRUE It has sense key.
2908 @retval FALSE It has NOT any sense key.
2909
2910 **/
2911 BOOLEAN
2912 ScsiDiskHaveSenseKey (
2913 IN EFI_SCSI_SENSE_DATA *SenseData,
2914 IN UINTN SenseCounts
2915 )
2916 {
2917 EFI_SCSI_SENSE_DATA *SensePtr;
2918 UINTN Index;
2919 BOOLEAN HaveSenseKey;
2920
2921 if (SenseCounts == 0) {
2922 HaveSenseKey = FALSE;
2923 } else {
2924 HaveSenseKey = TRUE;
2925 }
2926
2927 SensePtr = SenseData;
2928
2929 for (Index = 0; Index < SenseCounts; Index++) {
2930
2931 //
2932 // Sense Key is SK_NO_SENSE (0x0)
2933 //
2934 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
2935 (Index == 0)) {
2936 HaveSenseKey = FALSE;
2937 }
2938
2939 SensePtr++;
2940 }
2941
2942 return HaveSenseKey;
2943 }
2944
2945 /**
2946 Release resource about disk device.
2947
2948 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2949
2950 **/
2951 VOID
2952 ReleaseScsiDiskDeviceResources (
2953 IN SCSI_DISK_DEV *ScsiDiskDevice
2954 )
2955 {
2956 if (ScsiDiskDevice == NULL) {
2957 return ;
2958 }
2959
2960 if (ScsiDiskDevice->SenseData != NULL) {
2961 FreePool (ScsiDiskDevice->SenseData);
2962 ScsiDiskDevice->SenseData = NULL;
2963 }
2964
2965 if (ScsiDiskDevice->ControllerNameTable != NULL) {
2966 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
2967 ScsiDiskDevice->ControllerNameTable = NULL;
2968 }
2969
2970 FreePool (ScsiDiskDevice);
2971
2972 ScsiDiskDevice = NULL;
2973 }
2974
2975 /**
2976 Determine if Block Io should be produced.
2977
2978
2979 @param ChildHandle Child Handle to retrieve Parent information.
2980
2981 @retval TRUE Should produce Block Io.
2982 @retval FALSE Should not produce Block Io.
2983
2984 **/
2985 BOOLEAN
2986 DetermineInstallBlockIo (
2987 IN EFI_HANDLE ChildHandle
2988 )
2989 {
2990 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
2991 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
2992
2993 //
2994 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2995 // check its attribute, logic or physical.
2996 //
2997 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
2998 if (ExtScsiPassThru != NULL) {
2999 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
3000 return TRUE;
3001 }
3002 }
3003
3004 //
3005 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
3006 // check its attribute, logic or physical.
3007 //
3008 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
3009 if (ScsiPassThru != NULL) {
3010 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
3011 return TRUE;
3012 }
3013 }
3014
3015 return FALSE;
3016 }
3017
3018 /**
3019 Search protocol database and check to see if the protocol
3020 specified by ProtocolGuid is present on a ControllerHandle and opened by
3021 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
3022 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
3023 will be opened on it.
3024
3025
3026 @param ProtocolGuid ProtocolGuid pointer.
3027 @param ChildHandle Child Handle to retrieve Parent information.
3028
3029 **/
3030 VOID *
3031 EFIAPI
3032 GetParentProtocol (
3033 IN EFI_GUID *ProtocolGuid,
3034 IN EFI_HANDLE ChildHandle
3035 )
3036 {
3037 UINTN Index;
3038 UINTN HandleCount;
3039 VOID *Interface;
3040 EFI_STATUS Status;
3041 EFI_HANDLE *HandleBuffer;
3042
3043 //
3044 // Retrieve the list of all handles from the handle database
3045 //
3046 Status = gBS->LocateHandleBuffer (
3047 ByProtocol,
3048 ProtocolGuid,
3049 NULL,
3050 &HandleCount,
3051 &HandleBuffer
3052 );
3053
3054 if (EFI_ERROR (Status)) {
3055 return NULL;
3056 }
3057
3058 //
3059 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
3060 //
3061 for (Index = 0; Index < HandleCount; Index++) {
3062 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
3063 if (!EFI_ERROR (Status)) {
3064 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
3065 if (!EFI_ERROR (Status)) {
3066 gBS->FreePool (HandleBuffer);
3067 return Interface;
3068 }
3069 }
3070 }
3071
3072 gBS->FreePool (HandleBuffer);
3073 return NULL;
3074 }
3075
3076 /**
3077 Provides inquiry information for the controller type.
3078
3079 This function is used by the IDE bus driver to get inquiry data. Data format
3080 of Identify data is defined by the Interface GUID.
3081
3082 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3083 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
3084 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
3085
3086 @retval EFI_SUCCESS The command was accepted without any errors.
3087 @retval EFI_NOT_FOUND Device does not support this data class
3088 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
3089 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
3090
3091 **/
3092 EFI_STATUS
3093 EFIAPI
3094 ScsiDiskInfoInquiry (
3095 IN EFI_DISK_INFO_PROTOCOL *This,
3096 IN OUT VOID *InquiryData,
3097 IN OUT UINT32 *InquiryDataSize
3098 )
3099 {
3100 EFI_STATUS Status;
3101 SCSI_DISK_DEV *ScsiDiskDevice;
3102
3103 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
3104
3105 Status = EFI_BUFFER_TOO_SMALL;
3106 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
3107 Status = EFI_SUCCESS;
3108 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
3109 }
3110 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
3111 return Status;
3112 }
3113
3114
3115 /**
3116 Provides identify information for the controller type.
3117
3118 This function is used by the IDE bus driver to get identify data. Data format
3119 of Identify data is defined by the Interface GUID.
3120
3121 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
3122 instance.
3123 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
3124 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
3125 size.
3126
3127 @retval EFI_SUCCESS The command was accepted without any errors.
3128 @retval EFI_NOT_FOUND Device does not support this data class
3129 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
3130 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
3131
3132 **/
3133 EFI_STATUS
3134 EFIAPI
3135 ScsiDiskInfoIdentify (
3136 IN EFI_DISK_INFO_PROTOCOL *This,
3137 IN OUT VOID *IdentifyData,
3138 IN OUT UINT32 *IdentifyDataSize
3139 )
3140 {
3141 EFI_STATUS Status;
3142 SCSI_DISK_DEV *ScsiDiskDevice;
3143
3144 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
3145 //
3146 // Physical SCSI bus does not support this data class.
3147 //
3148 return EFI_NOT_FOUND;
3149 }
3150
3151 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
3152
3153 Status = EFI_BUFFER_TOO_SMALL;
3154 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
3155 Status = EFI_SUCCESS;
3156 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
3157 }
3158 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
3159 return Status;
3160 }
3161
3162 /**
3163 Provides sense data information for the controller type.
3164
3165 This function is used by the IDE bus driver to get sense data.
3166 Data format of Sense data is defined by the Interface GUID.
3167
3168 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3169 @param[in, out] SenseData Pointer to the SenseData.
3170 @param[in, out] SenseDataSize Size of SenseData in bytes.
3171 @param[out] SenseDataNumber Pointer to the value for the sense data size.
3172
3173 @retval EFI_SUCCESS The command was accepted without any errors.
3174 @retval EFI_NOT_FOUND Device does not support this data class.
3175 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
3176 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
3177
3178 **/
3179 EFI_STATUS
3180 EFIAPI
3181 ScsiDiskInfoSenseData (
3182 IN EFI_DISK_INFO_PROTOCOL *This,
3183 IN OUT VOID *SenseData,
3184 IN OUT UINT32 *SenseDataSize,
3185 OUT UINT8 *SenseDataNumber
3186 )
3187 {
3188 return EFI_NOT_FOUND;
3189 }
3190
3191
3192 /**
3193 This function is used by the IDE bus driver to get controller information.
3194
3195 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3196 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
3197 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
3198
3199 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
3200 @retval EFI_UNSUPPORTED This is not an IDE device.
3201
3202 **/
3203 EFI_STATUS
3204 EFIAPI
3205 ScsiDiskInfoWhichIde (
3206 IN EFI_DISK_INFO_PROTOCOL *This,
3207 OUT UINT32 *IdeChannel,
3208 OUT UINT32 *IdeDevice
3209 )
3210 {
3211 SCSI_DISK_DEV *ScsiDiskDevice;
3212
3213 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
3214 //
3215 // This is not an IDE physical device.
3216 //
3217 return EFI_UNSUPPORTED;
3218 }
3219
3220 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
3221 *IdeChannel = ScsiDiskDevice->Channel;
3222 *IdeDevice = ScsiDiskDevice->Device;
3223
3224 return EFI_SUCCESS;
3225 }
3226
3227
3228 /**
3229 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
3230
3231 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
3232 implement Identify() interface for DiskInfo protocol. The ATA command is sent
3233 via SCSI Request Packet.
3234
3235 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3236
3237 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
3238 @retval others Some error occurred during the identification that ATAPI device.
3239
3240 **/
3241 EFI_STATUS
3242 AtapiIdentifyDevice (
3243 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
3244 )
3245 {
3246 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
3247 UINT8 Cdb[6];
3248
3249 //
3250 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
3251 //
3252 ZeroMem (&CommandPacket, sizeof (CommandPacket));
3253 ZeroMem (Cdb, sizeof (Cdb));
3254
3255 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
3256 CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
3257 CommandPacket.Cdb = Cdb;
3258 CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
3259 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
3260 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
3261
3262 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
3263 }
3264
3265
3266 /**
3267 Initialize the installation of DiskInfo protocol.
3268
3269 This function prepares for the installation of DiskInfo protocol on the child handle.
3270 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
3271 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
3272 to be IDE/AHCI interface GUID.
3273
3274 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3275 @param ChildHandle Child handle to install DiskInfo protocol.
3276
3277 **/
3278 VOID
3279 InitializeInstallDiskInfo (
3280 IN SCSI_DISK_DEV *ScsiDiskDevice,
3281 IN EFI_HANDLE ChildHandle
3282 )
3283 {
3284 EFI_STATUS Status;
3285 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
3286 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
3287 ATAPI_DEVICE_PATH *AtapiDevicePath;
3288 SATA_DEVICE_PATH *SataDevicePath;
3289 UINTN IdentifyRetry;
3290
3291 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
3292 //
3293 // Device Path protocol must be installed on the device handle.
3294 //
3295 ASSERT_EFI_ERROR (Status);
3296 //
3297 // Copy the DiskInfo protocol template.
3298 //
3299 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
3300
3301 while (!IsDevicePathEnd (DevicePathNode)) {
3302 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
3303 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
3304 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
3305 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
3306 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
3307 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
3308
3309 IdentifyRetry = 3;
3310 do {
3311 //
3312 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
3313 // with IDE/AHCI interface GUID.
3314 //
3315 Status = AtapiIdentifyDevice (ScsiDiskDevice);
3316 if (!EFI_ERROR (Status)) {
3317 if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
3318 //
3319 // We find the valid ATAPI device path
3320 //
3321 AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
3322 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
3323 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
3324 //
3325 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
3326 //
3327 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
3328 } else {
3329 //
3330 // We find the valid SATA device path
3331 //
3332 SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
3333 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
3334 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
3335 //
3336 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
3337 //
3338 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
3339 }
3340 return;
3341 }
3342 } while (--IdentifyRetry > 0);
3343 } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
3344 (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) {
3345 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
3346 break;
3347 }
3348 DevicePathNode = ChildDevicePathNode;
3349 }
3350
3351 return;
3352 }