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